Merge branch 'tagview'

This commit is contained in:
Joseph Schorr 2015-03-16 17:14:43 -04:00
commit 3c305beeea
160 changed files with 151133 additions and 497 deletions

View file

@ -5,7 +5,7 @@
<!-- Side information -->
<div class="build-side-info">
<!-- Build ID -->
<div class="build-side-id">{{ build.id }}</div>
<div class="build-side-id" ng-if="!hideId">{{ build.id }}</div>
<!-- Timing -->
<div class="timing" ng-if="showTime">

View file

@ -0,0 +1,10 @@
<a class="build-mini-status-element" href="/repository/{{ build.repository.namespace }}/{{ build.repository.name }}/build/{{ build.id }}">
<div>
<span class="build-state-icon" build="build"></span>
<span class="timing">
<i class="fa fa-clock-o"></i><span am-time-ago="build.started || 0"></span>
</span>
<div class="build-description triggered-build-description" build="build"></div>
</div>
</a>

View file

@ -0,0 +1,8 @@
<span class="build-state-icon-element" ng-class="build.phase">
<span class="cor-loader-inline" ng-if="isBuilding(build)"></span>
<span ng-if="!isBuilding(build)">
<i class="fa fa-check-circle" ng-if="build.phase == 'complete'"></i>
<i class="fa fa-times-circle" ng-if="build.phase == 'error'"></i>
<i class="fa fa-exclamation-circle" ng-if="build.phase == 'internalerror'"></i>
</span>
</span>

View file

@ -1,3 +1,4 @@
<!-- NOTE: DEPRECATED -->
<div id="build-status-container" class="build-status-container">
<div>
<span class="phase-icon" ng-class="build.phase"></span>

View file

@ -0,0 +1,3 @@
<span class="co-checkable-item" ng-click="toggleItem()"
ng-class="controller.isChecked(item, controller.checked) ? 'checked': 'not-checked'">
</span>

View file

@ -0,0 +1 @@
<li><a href="javascript:void(0)" ng-click="selected()"><span ng-transclude/></a></li>

View file

@ -0,0 +1,12 @@
<span class="co-checkable-menu">
<span class="dropdown" style="text-align: left;">
<span class="btn btn-default" data-toggle="dropdown">
<span class="co-checkable-menu-state"
ng-class="getClass(controller.items, controller.checked)"
ng-click="toggleItems($event)">
</span>
<span class="caret"></span>
</span>
<ul class="dropdown-menu" ng-transclude></ul>
</span>
</span>

View file

@ -0,0 +1,25 @@
<div class="cor-confirm-dialog-element">
<div class="modal fade co-dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-show="!working"
data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{{ dialogTitle }}</h4>
</div>
<div class="modal-body" ng-show="working">
<div class="cor-loader"></div>
</div>
<div class="modal-body" ng-show="!working">
<span ng-transclude/>
</div>
<div class="modal-footer" ng-show="!working">
<button type="button" class="btn btn-primary" ng-click="performAction()">
{{ dialogActionTitle }}
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</div>

View file

@ -1,3 +1,3 @@
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-6">
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-1">
<span class="co-nav-title-action co-fx-text-shadow" ng-transclude></span>
</div>

View file

@ -1 +1 @@
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-6" ng-transclude></div>
<div class="col-lg-3 col-md-3 col-sm-3 hidden-xs" ng-transclude></div>

View file

@ -0,0 +1,3 @@
<span class="filter-control-element" ng-class="filter == value ? 'selected': 'not-selected'">
<a href="javascript:void(0)" ng-click="setFilter()"><span ng-transclude/></a>
</span>

View file

@ -0,0 +1,33 @@
<div class="image-changes-view-element">
<div class="resource-view" resource="imageChangesResource">
<div class="changes-container" ng-show="hasChanges">
<span class="change-count added"
ng-show="changeData.added.length > 0"
data-title="Files Added"
data-placement="top"
data-container="body"
bs-tooltip>
<i class="fa fa-plus-square"></i>
<b>{{ changeData.added.length }}</b>
</span>
<span class="change-count removed"
ng-show="changeData.removed.length > 0"
data-title="Files Removed"
data-placement="top"
data-container="body"
bs-tooltip>
<i class="fa fa-minus-square"></i>
<b>{{ changeData.removed.length }}</b>
</span>
<span class="change-count changed"
ng-show="changeData.changed.length > 0"
data-title="Files Changes"
data-placement="top"
data-container="body"
bs-tooltip>
<i class="fa fa-pencil-square"></i>
<b>{{ changeData.changed.length }}</b>
</span>
</div>
</div>
</div>

View file

@ -0,0 +1,105 @@
<div class="image-info-sidebar-element">
<!-- Comment -->
<div class="image-comment" ng-if="imageData.comment">
<blockquote style="margin-top: 10px;">
<span class="markdown-view" content="imageData.comment"></span>
</blockquote>
</div>
<!-- Image ID -->
<div class="image-section">
<i class="fa fa-code section-icon" bs-tooltip="tooltip.title" data-title="Full Image ID"></i>
<span class="section-info">
<a class="image-link" ng-href="{{ tracker.imageLink(image) }}">
{{ imageData.id }}
</a>
</span>
</div>
<!-- Tags -->
<div class="image-section">
<i class="fa fa-tag section-icon" data-title="Current Tags" bs-tooltip></i>
<span class="section-info section-info-with-dropdown">
<a class="label tag label-default" ng-repeat="tag in imageData.tags"
href="javascript:void(0)" ng-click="tagSelected({'tag': tag})">
{{ tag }}
</a>
<span style="color: #ccc;" ng-if="!imageData.tags.length">(No Tags)</span>
<div class="dropdown" data-placement="top"
ng-if="tracker.repository.can_write || imageData.tags">
<a href="javascript:void(0)" class="dropdown-button" data-toggle="dropdown"
bs-tooltip="tooltip.title" data-title="Manage Tags"
data-container="body">
<b class="caret"></b>
</a>
<ul class="dropdown-menu pull-right">
<li ng-repeat="tag in imageData.tags">
<a href="javascript:void(0)" ng-click="tagSelected({'tag': tag})">
<i class="fa fa-tag"></i>{{ tag }}
</a>
</li>
<li class="divider" role="presentation"
ng-if="tracker.repository.can_write && imageData.tags"></li>
<li>
<a href="javascript:void(0)"
ng-click="addTagRequested({'image': image})"
ng-if="tracker.repository.can_write">
<i class="fa fa-plus"></i>Add New Tag
</a>
</li>
</ul>
</div>
</span>
</div>
<!-- Command -->
<div class="image-section" ng-if="imageData.command && imageData.command.length">
<i class="fa fa-terminal section-icon" data-title="Image Command" bs-tooltip></i>
<span class="section-info">
<span class="formatted-command trimmed"
data-html="true"
data-title="{{ getTooltipCommand(imageData) }}"
data-placement="top" bs-tooltip>{{ getFormattedCommand(imageData) }}</span>
</span>
</div>
<!-- Created -->
<div class="image-section">
<i class="fa fa-calendar section-icon" data-title="Created" bs-tooltip></i>
<span class="section-info">
<dd am-time-ago="parseDate(imageData.created)"></dd>
</span>
</div>
<!-- Size -->
<div class="image-section">
<i class="fa fa-cloud-upload section-icon"
data-title="The amount of data sent between Docker and the registry when pushing/pulling"
bs-tooltip></i>
<span class="section-info">{{ imageData.size | bytes }}</span>
</div>
<!-- Locations -->
<div class="image-section">
<i class="fa fa-map-marker section-icon"
data-title="The geographic region(s) in which this image data is located"
bs-tooltip></i>
<span class="section-info">
<span class="location-view" location="location"
ng-repeat="location in imageData.locations"></span>
</span>
</div>
<!-- Changes -->
<div class="image-section" ng-show="hasImageChanges">
<i class="fa fa-code-fork section-icon"
data-title="File Changes"
bs-tooltip></i>
<span class="section-info">
<div class="image-changes-view" repository="tracker.repository" image="image"
has-changes="hasImageChanges"></div>
</span>
</div>
</div>

View file

@ -1,7 +1,7 @@
<div class="markdown-input-container">
<p ng-class="'lead ' + (canWrite ? 'editable' : 'noteditable')" ng-click="editContent()">
<span class="markdown-view" content="content"></span>
<span class="empty" ng-show="!content && canWrite">(Click to set {{ fieldTitle }})</span>
<span class="empty" ng-show="!content && canWrite">Click to set {{ fieldTitle }}</span>
<i class="fa fa-edit"></i>
</p>

View file

@ -30,7 +30,8 @@
</a>
</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">
<i ng-class="repository.is_starred ? 'starred fa fa-star' : 'fa fa-star-o'" class="star-icon" ng-click="toggleStar({repository: repository})"></i>
<span class="repo-star" repository="repository"
star-toggled="starToggled({'repository': repository})"></span>
</div>
</div>
<div class="description markdown-view" content="repository.description" first-line-only="true" placeholder-needed="true"></div>

View file

@ -0,0 +1,5 @@
<span class="repo-star-element">
<i ng-class="repository.is_starred ? 'starred fa fa-star' : 'fa fa-star-o'"
class="star-icon" ng-click="toggleStar()">
</i>
</span>

View file

@ -0,0 +1,187 @@
<div class="repo-panel-builds-element">
<div class="tab-header-controls">
<button class="btn btn-primary" ng-click="showNewBuildDialog()">
<i class="fa fa-plus"></i>Start Build
</button>
</div>
<h3 class="tab-header">Repository Builds</h3>
<!-- Builds -->
<div class="co-panel">
<!-- Builds header controls -->
<div class="co-panel-heading">
<div class="heading-controls hidden-sm hidden-xs">
<span class="filter-control" filter="options.filter" value="recent">Recent Builds</span>
<span class="filter-control" filter="options.filter" value="48hour">Last 48 Hours</span>
<span class="filter-control" filter="options.filter" value="30day">Last 30 days</span>
</div>
<div class="heading-title">
<i class="fa fa-tasks"></i>
Build History
</div>
</div>
<!-- Builds list content -->
<div class="panel-body">
<div class="resource-view" resource="buildsResource" error-message="'Could not load build information'">
<!-- No builds found -->
<div class="empty" ng-if="!fullBuilds.length">
<div class="empty-primary-msg">No matching builds found</div>
<div class="empty-secondary-msg">
Please change the filter above to search for more builds.
</div>
</div>
<!-- Builds list table -->
<table class="co-table" ng-if="fullBuilds.length">
<thead>
<td class="status-col"></td>
<td ng-class="tablePredicateClass('id', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('id')">Build ID</a>
</td>
<td ng-class="tablePredicateClass('tags', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('tags')">Tags</a>
</td>
<td ng-class="tablePredicateClass('commit_sha', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('commit_sha')">Triggered By</a>
</td>
<td ng-class="tablePredicateClass('started_datetime', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('started_datetime')">Date Started</a>
</td>
<td class="options-col"></td>
</thead>
<tr ng-repeat="build in fullBuilds">
<td><span class="build-state-icon" build="build"></span></td>
<td>
<a href="/repository/{{ repository.namespace }}/{{ repository.name }}/build/{{ build.id }}">{{ build.id.substr(0, 8) }}</a>
</td>
<td>
<span class="building-tag" ng-repeat="tag in build.building_tags">
<i class="fa fa-tag"></i>{{ tag }}
</span>
</td>
<td>
<div class="triggered-build-description" build="build"></div>
</td>
<td>{{ build.started | amCalendar }}</td>
</tr>
</table>
</div>
</div>
</div> <!-- /Builds -->
<!-- Build Triggers -->
<div class="co-panel" ng-if="repository.can_admin && TriggerService.getTypes().length">
<!-- Builds header controls -->
<div class="co-panel-heading">
<i class="fa fa-flash"></i>
Build Triggers
<div class="heading-controls hidden-sm hidden-xs">
<!-- Add Build Trigger -->
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
Create Build Trigger
<b class="caret"></b>
</button>
<ul class="dropdown-menu dropdown-menu-right pull-right">
<li ng-repeat="type in TriggerService.getTypes()">
<a href="{{ TriggerService.getRedirectUrl(type, repository.namespace, repository.name) }}">
<i class="fa fa-lg" ng-class="TriggerService.getMetadata(type).icon"></i>
{{ TriggerService.getTitle(type) }}
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- Builds list content -->
<div class="panel-body">
<div class="resource-view" resource="triggersResource" error-message="'Could not load build triggers'">
<!-- No Triggers defined -->
<div class="empty" ng-if="!triggers.length">
<div class="empty-primary-msg">No build triggers defined</div>
<div class="empty-secondary-msg">
Build triggers invoke builds whenever the triggered condition is met (source control push, webhook, etc)
</div>
</div>
<!-- Triggers list -->
<table class="co-table" ng-if="triggers.length">
<thead>
<td>Trigger Name</td>
<td>Dockerfile Location</td>
<td>Branches/Tags</td>
<td>Pull Robot</td>
<td class="options-col"></td>
</thead>
<tr ng-repeat="trigger in triggers | filter:{'is_active':false}">
<td colspan="5" style="text-align: center">
<span class="cor-loader-inline"></span>
Trigger Setup in progress:
<a href="javascript:void(0)" ng-click="setupTrigger(trigger)">Resume</a> |
<a href="javascript:void(0)" ng-click="deleteTrigger(trigger)">Cancel</a>
</td>
</tr>
<tr ng-repeat="trigger in triggers | filter:{'is_active':true}">
<td><div class="trigger-description" trigger="trigger" short="true"></div></td>
<td>{{ trigger.subdir || '(Root Directory)' }}</td>
<td>{{ trigger.config.branchtag_regex || '(All)' }}</td>
<td>
<span class="entity-reference" entity="trigger.pull_robot" ng-if="trigger.pull_robot"></span>
</td>
<td>
<span class="cor-options-menu">
<span class="cor-option" option-click="askRunTrigger(trigger)">
<i class="fa fa-chevron-right"></i> Run Trigger Now
</span>
<span class="cor-option" option-click="askDeleteTrigger(trigger)">
<i class="fa fa-times"></i> Delete Trigger
</span>
</span>
</td>
</tr>
</table>
</div>
</div>
</div> <!-- /Build Triggers -->
<!-- Delete Tag Confirm -->
<div class="cor-confirm-dialog"
dialog-context="deleteTriggerInfo"
dialog-action="deleteTrigger(info.trigger, callback)"
dialog-title="Delete Build Trigger"
dialog-action-title="Delete Trigger">
Are you sure you want to delete this build trigger? No further builds will be automatically
started.
</div>
<!-- Dockerfile build dialog -->
<div class="dockerfile-build-dialog"
show-now="showBuildDialogCounter"
repository="repository"
build-started="handleBuildStarted(build)">
</div>
<!-- Setup trigger dialog-->
<div class="setup-trigger-dialog"
repository="repository"
trigger="currentSetupTrigger"
canceled="cancelSetupTrigger(trigger)"
counter="showTriggerSetupCounter"></div>
<!-- Manual trigger dialog -->
<div class="manual-trigger-build-dialog"
repository="repository"
trigger="currentStartTrigger"
counter="showTriggerStartDialogCounter"
start-build="startTrigger(trigger, parameters)"></div>
</div>

View file

@ -0,0 +1,63 @@
<div class="repo-panel-changes-element">
<!-- No Tags Selected -->
<div class="empty" ng-if="!selectedTags.length">
<div class="empty-primary-msg">No tags selected to view</div>
<div class="empty-secondary-msg">
Please select one or more tags in the <i class="fa fa-tags" style="margin-left: 4px; margin-right: 4px;"></i> Tags tab to visualize.
</div>
</div>
<!-- Tags Selected -->
<div ng-if="selectedTags.length > 0">
<h3 class="tab-header">
Visualize Tags:
<span class="visualized-tag" ng-repeat="tag in selectedTags">
<i class="fa fa-tag"></i>{{ tag }}
</span>
</h3>
<div id="image-history row" class="resource-view" resource="imagesResource"
error-message="'Cannot load repository images'">
<!-- Tree View container -->
<div class="col-md-8">
<div class="panel panel-default">
<!-- Image history tree -->
<div id="image-history-container" onresize="tree.notifyResized()"></div>
</div>
</div>
<!-- Side Panel -->
<div class="col-md-4">
<div class="side-panel-title" ng-if="currentTag">
<i class="fa fa-tag"></i>{{ currentTag }}
</div>
<div class="side-panel-title" ng-if="currentImage">
<i class="fa fa-archive"></i>{{ currentImage.substr(0, 12) }}
</div>
<div class="side-panel">
<!-- Tag Info -->
<div class="tag-info-sidebar"
tracker="tracker"
tag="currentTag"
image-selected="setImage(image)"
delete-tag-requested="tagActionHandler.askDeleteTag(tag)"
ng-if="currentTag">
</div>
<!-- Image Info -->
<div class="image-info-sidebar"
tracker="tracker"
image="currentImage"
tag-selected="setTag(tag)"
add-tag-requested="tagActionHandler.askAddTag(image)"
ng-if="currentImage">
</div>
</div>
</div>
</div>
</div>
<div class="tag-operations-dialog" repository="repository" images="images"
action-handler="tagActionHandler" tag-changed="handleTagChanged(data)"></div>

View file

@ -0,0 +1,72 @@
<div class="repo-panel-info-element">
<!-- Repository stats and builds summary -->
<div class="repository-stats row">
<!-- Pull Stats -->
<div class="col-sm-3 stat-col">
<div class="stat-title">Repo Pulls</div>
<div class="stat">
<div class="stat-value">{{ repository.stats.pulls.today }}</div>
<div class="stat-subtitle">Last 24 hours</div>
</div>
<div class="stat">
<div class="stat-value">{{ repository.stats.pulls.thirty_day }}</div>
<div class="stat-subtitle">Last 30 days</div>
</div>
</div>
<!-- Push Stats -->
<div class="col-sm-3 stat-col">
<div class="stat-title">Repo Pushes</div>
<div class="stat">
<div class="stat-value">{{ repository.stats.pushes.today }}</div>
<div class="stat-subtitle">Last 24 hours</div>
</div>
<div class="stat">
<div class="stat-value">{{ repository.stats.pushes.thirty_day }}</div>
<div class="stat-subtitle">Last 30 days</div>
</div>
</div>
<!-- Builds -->
<div class="col-sm-6">
<div class="stat-title">Recent Repo Builds</div>
<!-- Loading -->
<div class="cor-loader" ng-if="!builds"></div>
<!-- No Builds -->
<div class="empty" ng-if="builds && !builds.length">
<div class="empty-primary-msg">No builds have been run for this repository.</div>
<div class="empty-secondary-msg" ng-if="repository.can_write">
Click on the <i class="fa fa-tasks" style="margin-left: 6px"></i> Builds tab to start a new build.
</div>
</div>
<!-- Builds -->
<div ng-if="builds && builds.length">
<div class="build-mini-status" ng-repeat="build in builds" build="build"></div>
</div>
<!-- View All -->
<a href="/repository/{{ repository.namespace }}/{{ repository.name }}?tab=builds"
class="view-all" ng-if="repository.can_admin && builds.length">
View Build History
</a>
</div>
</div>
<!-- Repository Description -->
<div class="description-container">
<h4 style="font-size:20px;">Description</h4>
<div class="description markdown-input"
content="repository.description"
can-write="repository.can_write"
content-changed="updateDescription"
field-title="'repository description'">
</div>
</div>
</div>

View file

@ -0,0 +1,95 @@
<div class="repo-panel-settings-element">
<h3 class="tab-header">Repository Settings</h3>
<!-- User/Team Permissions -->
<div class="co-panel">
<div class="co-panel-heading"><i class="fa fa-key"></i> User and Robot Permissions</div>
<div class="panel-body">
<div class="repository-permissions-table" repository="repository"></div>
</div>
</div>
<!-- Access Tokens (DEPRECATED) -->
<div class="co-panel" ng-show="hasTokens">
<div class="co-panel-heading"><i class="fa fa-key"></i> Access Token Permissions</div>
<div class="panel-body">
<div class="repository-tokens-table" repository="repository" has-tokens="hasTokens"></div>
</div>
</div>
<!-- Events and Notifications -->
<div class="repository-events-table" repository="repository"></div>
<!-- Other settings -->
<div class="co-panel">
<div class="co-panel-heading"><i class="fa fa-gears"></i> Repository Settings</div>
<div class="cor-loader" ng-show="!repository"></div>
<div ng-show="repository">
<!-- Public/Private -->
<div class="panel-body panel-section lock-section" ng-if="!repository.is_public">
<i class="fa fa-lock lock-icon"></i>
<div>This repository is currently <b>private</b>. Only users on the permissions list may view and interact with it.</div>
<button class="btn btn-default" ng-click="askChangeAccess('public')">
<i class="fa fa-unlock"></i>Make Public
</button>
</div>
<div class="panel-body panel-section lock-section" ng-if="repository.is_public">
<i class="fa fa-unlock lock-icon"></i>
<div>This repository is currently <b>public</b> and is visible to all users, and may be pulled by all users.</div>
<button class="btn btn-default" ng-click="askChangeAccess('private')">
<i class="fa fa-lock"></i>Make Private
</button>
</div>
<!-- Delete Repository -->
<div class="panel-body panel-section">
<div>Deleting a repository <b>cannot be undone</b>. Here be dragons!</div>
<button class="btn btn-danger" ng-click="askDelete()">
<i class="fa fa-trash"></i>
Delete Repository
</button>
</div>
<!-- Build Status Badge -->
<div class="panel-body panel-section">
<!-- Status Image -->
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}">
<img ng-src="/repository/{{ repository.namespace }}/{{ repository.name }}/status?token={{ repository.status_token }}"
data-title="Docker Repository on Quay.io">
</a>
<!-- Embed formats -->
<table style="margin-top: 20px; width: 600px;">
<thead>
<th style="width: 150px"></th>
<th></th>
</thead>
<tr>
<td>Image (SVG):</td>
<td>
<div class="copy-box" hovering-message="true" value="getBadgeFormat('svg', repository)"></div>
</td>
</tr>
<tr>
<td>Markdown:</td>
<td>
<div class="copy-box" hovering-message="true" value="getBadgeFormat('md', repository)"></div>
</td>
</tr>
<tr>
<td>AsciiDoc:</td>
<td>
<div class="copy-box" hovering-message="true" value="getBadgeFormat('asciidoc', repository)"></div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,99 @@
<div class="repo-panel-tags-element">
<h3 class="tab-header">Repository Tags</h3>
<div class="resource-view" resource="imagesResource" error-message="'Could not load images'">
<div class="co-check-bar">
<span class="cor-checkable-menu" controller="checkedTags">
<div class="cor-checkable-menu-item" item-filter="allTagFilter">
<i class="fa fa-check-square-o"></i>All Tags
</div>
<div class="cor-checkable-menu-item" item-filter="noTagFilter(tag)">
<i class="fa fa-square-o"></i>No Tags
</div>
<div class="cor-checkable-menu-item" item-filter="commitTagFilter(tag)">
<i class="fa fa-git"></i>Commit SHAs
</div>
<div class="cor-checkable-menu-item" item-filter="imageIDFilter(it.image_id, tag)"
ng-repeat="it in imageTracks">
<i class="fa fa-circle-o" ng-style="{'color': it.color}"></i> {{ it.image_id.substr(0, 12) }}
</div>
</span>
<span class="co-checked-actions" ng-if="checkedTags.checked.length">
<a href="javascript:void(0)" class="btn btn-default" ng-click="setTab('changes')">
<i class="fa fa-code-fork"></i> Visualize
</a>
<button class="btn btn-default"
ng-click="askDeleteMultipleTags(checkedTags.checked)"
ng-if="repository.can_write">
<i class="fa fa-times"></i> Delete
</button>
</span>
<span class="co-filter-box">
<input class="form-control" type="text" ng-model="options.tagFilter" placeholder="Filter Tags...">
</span>
</div>
<table class="co-table">
<thead>
<td class="checkbox-col"></td>
<td ng-class="tablePredicateClass('name', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('name')">Tag</a>
</td>
<td ng-class="tablePredicateClass('last_modified_datetime', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('last_modified_datetime')">Last Modified</a>
</td>
<td ng-class="tablePredicateClass('size', options.predicate, options.reverse)">
<a href="javascript:void(0)" ng-click="orderBy('size')">Size</a>
</td>
<td ng-class="tablePredicateClass('image_id', options.predicate, options.reverse)"
colspan="{{ imageTracks.length + 1 }}">
<a href="javascript:void(0)" ng-click="orderBy('image_id')">Image</a>
</td>
<td class="options-col"></td>
</thead>
<tr class="co-checkable-row"
ng-repeat="tag in tags"
ng-class="checkedTags.isChecked(tag, checkedTags.checked) ? 'checked' : ''">
<td><span class="cor-checkable-item" controller="checkedTags" item="tag"></span></td>
<td><i class="fa fa-tag"></i> {{ tag.name }}</td>
<td><span am-time-ago="tag.last_modified"></span></td>
<td>{{ tag.size | bytes }}</td>
<td class="image-id-col">
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}/image/{{ tag.image_id }}">
{{ tag.image_id.substr(0, 12) }}
</a>
</td>
<td class="image-track" ng-repeat="it in imageTracks">
<span class="image-track-dot" ng-if="it.image_id == tag.image_id"
ng-style="{'borderColor': it.color}"></span>
<span class="image-track-line" ng-class="trackLineClass($parent.$index, it)"
ng-style="{'borderColor': it.color}"></span>
</td>
<td class="options-col">
<span class="cor-options-menu" ng-if="repository.can_write">
<span class="cor-option" option-click="askDeleteTag(tag.name)">
<i class="fa fa-times"></i> Delete Tag
</span>
</span>
</td>
</tr>
</table>
<div class="empty" ng-if="allTags.length && !tags.length">
<div class="empty-primary-msg">No matching tags found.</div>
<div class="empty-secondary-msg">Try expanding your filtering terms.</div>
</div>
<div class="empty" ng-if="!allTags.length">
<div class="empty-primary-msg">This repository is empty.</div>
<div class="empty-secondary-msg">Push a tag or initiate a build to populate this repository.</div>
</div>
</div>
</div>
<div class="tag-operations-dialog" repository="repository" images="images"
action-handler="tagActionHandler"></div>

View file

@ -0,0 +1,75 @@
<div class="repository-events-table-element">
<div class="co-panel">
<div class="co-panel-heading">
<i class="fa fa-bell"></i> Events and Notifications
<div class="heading-controls hidden-sm hidden-xs">
<button class="btn btn-primary" ng-click="askCreateNotification()">
<i class="fa fa-plus"></i> Create Notification
</button>
</div>
</div>
<div class="panel-body">
<div class="resource-view" resource="notificationsResource"
error-message="'Could not load repository events'">
<div class="empty" ng-if="!notifications.length">
<div class="empty-primary-msg">No notification have been setup for this repository.</div>
<div class="empty-secondary-msg" ng-if="repository.can_write">
Click the "Create Notification" button above to add a new notification for a repository event.
</div>
</div>
<table class="co-table permissions" ng-if="notifications.length">
<thead>
<tr>
<td>Event</td>
<td>Notification</td>
<td class="options-col"></td>
</tr>
</thead>
<tbody>
<tr class="notification-row" ng-repeat="notification in notifications">
<td>
<span class="notification-event">
<i class="fa fa-lg" ng-class="getEventInfo(notification).icon"></i>
{{ getEventInfo(notification).title }}
</span>
</td>
<td>
<span class="notification-method">
<i class="fa fa-lg" ng-class="getMethodInfo(notification).icon"></i>
{{ getMethodInfo(notification).title }}
</span>
</td>
<td>
<span class="cor-options-menu">
<span class="cor-option" option-click="testNotification(notification)">
<i class="fa fa-send"></i> Test Notification
</span>
<span class="cor-option" option-click="showWebhookInfo(notification)"
ng-if="getMethodInfo(notification).id == 'webhook'">
<i class="fa fa-book"></i>
Webhook Documentation
</span>
<span class="cor-option" option-click="deleteNotification(notification)">
<i class="fa fa-times"></i> Delete Notification
</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- New notification dialog-->
<div class="create-external-notification-dialog"
repository="repository"
counter="showNewNotificationCounter"
notification-created="handleNotificationCreated(notification)"></div>
</div>

View file

@ -0,0 +1,82 @@
<div class="repository-permissions-table-element">
<div class="resource-view"
resources="[permissionResources.team, permissionResources.user]"
error-message="'Could not load repository permissions'">
<table class="co-table permissions">
<thead>
<tr>
<td>Account Name</td>
<td style="width: 300px">Permissions</td>
<td class="options-col"></td>
</tr>
</thead>
<!-- Team Permissions -->
<tr ng-repeat="(name, permission) in permissionResources.team.value">
<td class="team entity">
<span class="entity-reference" namespace="repository.namespace"
entity="buildEntityForPermission(name, permission, 'team')">
</span>
</td>
<td class="user-permissions">
<span class="role-group" current-role="permission.role" role-changed="setRole(role, name, 'team')" roles="roles"></span>
</td>
<td class="options-col">
<span class="cor-options-menu">
<span class="cor-option" option-click="deleteRole(name, 'team')">
<i class="fa fa-times"></i> Delete Permission
</span>
</span>
</td>
</tr>
<!-- User Permissions -->
<tr ng-repeat="(name, permission) in permissionResources.user.value">
<td class="{{ 'user entity ' + (permission.is_org_member ? '' : 'outside') }}">
<span class="entity-reference" namespace="repository.namespace"
entity="buildEntityForPermission(name, permission, 'user')">
</span>
</td>
<td class="user-permissions">
<div class="btn-group btn-group-sm">
<span class="role-group" current-role="permission.role" role-changed="setRole(role, name, 'user')" roles="roles"></span>
</div>
</td>
<td class="options-col">
<span class="cor-options-menu">
<span class="cor-option" option-click="deleteRole(name, 'user')">
<i class="fa fa-times"></i> Delete Permission
</span>
</span>
</td>
</tr>
<tr class="add-row">
<td id="add-entity-permission" class="admin-search">
<span class="entity-search" namespace="repository.namespace"
placeholder="'Select a ' + (repository.is_organization ? 'team or ' : '') + 'user...'"
current-entity="addPermissionInfo.entity"></span>
</td>
<td colspan="2">
<span class="role-group" current-role="addPermissionInfo.role" roles="roles"
role-changed="addPermissionInfo.role = role"></span>
<button class="btn btn-success" style="margin-left: 10px"
ng-disabled="!addPermissionInfo.role || !addPermissionInfo.entity"
ng-click="addPermission()">
Add Permission
</button>
</td>
</tr>
</table>
</div>
<!-- Grant Permission Confirm -->
<div class="cor-confirm-dialog"
dialog-context="grantPermissionInfo"
dialog-action="grantPermission(info.entity, callback)"
dialog-title="Grant Permission"
dialog-action-title="Grant Permission">
The selected user is outside of your organization. Are you sure you want to grant the user access to this repository?
</div>
</div>

View file

@ -0,0 +1,35 @@
<div class="repository-tokens-table-element">
<div class="resource-view" resource="tokensResource"
error-message="'Could not load repository tokens'">
<div class="alert alert-warning">Note: Access tokens are <strong>deprecated</strong> and will be removed in the near future. <a href="http://docs.quay.io/glossary/robot-accounts.html">Robot accounts</a> are the recommended replacement.
</div>
<table class="co-table permissions">
<thead>
<tr>
<td style="min-width: 400px;">Token Name</td>
<td>Permissions</td>
<td style="width: 95px;"></td>
</tr>
</thead>
<tbody>
<tr ng-repeat="(code, token) in tokens">
<td class="user token">
<i class="fa fa-key"></i>
<a ng-click="showToken(token.code)">{{ token.friendlyName }}</a>
</td>
<td class="user-permissions">
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-default" ng-click="changeTokenAccess(token.code, 'read')" ng-class="{read: 'active', write: ''}[token.role]">Read only</button>
<button type="button" class="btn btn-default" ng-click="changeTokenAccess(token.code, 'write')" ng-class="{read: '', write: 'active'}[token.role]">Write</button>
</div>
</td>
<td>
<span class="delete-ui" delete-title="'Delete Token'" perform-delete="deleteToken(token.code)"></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View file

@ -3,7 +3,7 @@
<div class="resource-error alert alert-info" ng-show="getState(resources) == 'error'">
{{ errorMessage }}
</div>
<div class="resource-content" ng-class="getState(resources) == 'ready' ? 'visible' : ''">
<div class="resource-content" ng-class="getState(resources) == 'ready' ? 'visible' : 'hidden'">
<span ng-transclude></span>
</div>
</div>

View file

@ -0,0 +1,42 @@
<div class="tag-info-sidebar-element">
<dl class="dl-normal">
<dt>Last Modified</dt>
<dd am-time-ago="parseDate(tagImage.created)"></dd>
<dt>Total Compressed Size</dt>
<dd>
<span class="context-tooltip"
data-title="The amount of data sent between Docker and the registry when pushing/pulling"
data-container="body"
bs-tooltip>
{{ tracker.getTotalSize(tag) | bytes }}
</span>
</dd>
</dl>
<div class="tag-image-sizes">
<div class="tag-image-size" ng-repeat="image in tracker.getImagesForTagBySize(tag) | limitTo: 10">
<span class="size-limiter">
<span class="size-bar"
ng-style="{'width': (image.size / tracker.getTotalSize(tag)) * 100 + '%'}"
data-title="{{ image.size | bytes }}"
bs-tooltip>
</span>
</span>
<span class="size-title">
<a class="image-size-link"
href="javascript:void(0)"
ng-click="imageSelected({'image': image.id})"
data-image="{{ image.id.substr(0, 12) }}">
{{ image.id.substr(0, 12) }}
</a>
</span>
</div>
</div>
<div class="control-bar" ng-show="tracker.repository.can_admin">
<button class="btn btn-default" ng-click="deleteTagRequested({'tag': tag})">
<i class="fa fa-times" style="margin-right: 6px;"></i>Delete Tag
</button>
</div>
</div>

View file

@ -0,0 +1,87 @@
<div class="tag-operations-dialog-element">
<!-- Add Tag Dialog -->
<div class="modal fade" id="createOrMoveTagModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true" ng-show="!addingTag">&times;</button>
<h4 class="modal-title">{{ isAnotherImageTag(toTagImage, tagToCreate) ? 'Move' : 'Add' }} Tag to Image {{ toTagImage.substr(0, 12) }}</h4>
</div>
<form name="addTagForm" ng-submit="createOrMoveTag(toTagImage, tagToCreate);">
<div class="modal-body">
<div class="cor-loader" ng-show="addingTag"></div>
<div ng-show="!addingTag">
<input type="text" class="form-control" id="tagName"
placeholder="Enter tag name"
ng-model="tagToCreate" ng-pattern="/^([a-z0-9_\.-]){3,30}$/"
ng-disabled="creatingTag" autofocus required>
<div style="margin: 10px; margin-top: 20px;"
ng-show="isOwnedTag(toTagImage, tagToCreate)">
Note: <span class="label tag label-default">{{ tagToCreate }}</span> is already applied to this image.
</div>
<div style="margin: 10px; margin-top: 20px;"
ng-show="isAnotherImageTag(toTagImage, tagToCreate)">
Note: <span class="label tag label-default">{{ tagToCreate }}</span> is already applied to another image. This will <b>move</b> the tag.
</div>
<div class="tag-specific-images-view"
tag="tagToCreate"
repository="repo"
images="images"
image-cutoff="toTagImage"
style="margin: 10px; margin-top: 20px; margin-bottom: -10px;"
ng-show="isAnotherImageTag(toTagImage, tagToCreate)">
This will also delete any unattach images and delete the following images:
</div>
</div>
</div>
<div class="modal-footer" ng-show="!addingTag">
<button type="submit" class="btn btn-primary"
ng-disabled="addTagForm.$invalid || isOwnedTag(toTagImage, tagToCreate)"
ng-class="isAnotherImageTag(toTagImage, tagToCreate) ? 'btn-warning' : 'btn-primary'"
ng-show="!creatingTag">
{{ isAnotherImageTag(toTagImage, tagToCreate) ? 'Move Tag' : 'Create Tag' }}
</button>
<button class="btn btn-default" data-dismiss="modal" ng-show="!addingTag">Cancel</button>
</div>
</form>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Delete Tags Confirm -->
<div class="cor-confirm-dialog"
dialog-context="deleteMultipleTagsInfo"
dialog-action="deleteMultipleTags(info.tags, callback)"
dialog-title="Delete Tags"
dialog-action-title="Delete Tags">
Are you sure you want to delete the following tags:
<ul>
<li ng-repeat="tag_info in deleteMultipleTagsInfo.tags">
<span class="label label-default tag">{{ tag_info.name }}</span>
</li>
</ul>
<div style="margin-top: 20px">
<strong>Note: </strong>This operation can take several minutes.
</div>
</div>
<!-- Delete Tag Confirm -->
<div class="cor-confirm-dialog"
dialog-context="deleteTagInfo"
dialog-action="deleteTag(info.tag, callback)"
dialog-title="Delete Tag"
dialog-action-title="Delete Tag">
Are you sure you want to delete tag
<span class="label label-default tag">{{ deleteTagInfo.tag }}</span>?
<div class="tag-specific-images-view" tag="deleteTagInfo.tag" repository="repository"
images="images" style="margin-top: 20px">
The following images and any other images not referenced by a tag will be deleted:
</div>
</div>
</div>

View file

@ -1,5 +1,14 @@
<div class="triggered-build-description-element">
<span ng-switch on="build.trigger.service">
<span class="manual" ng-if="!build.trigger && !build.job_config.manual_user">
(Manually Triggered Build)
</span>
<span ng-if="!build.trigger && build.job_config.manual_user">
<i class="fa fa-user"></i> {{ build.job_config.manual_user }}
</span>
<span ng-switch on="build.trigger.service" ng-if="build.trigger">
<!-- GitHub -->
<span ng-switch-when="github">
<!-- Full Commit Information -->