app/views/showRecipe.scala.html (201 lines of code) (raw):

@import data.Roles @import prism.Prism.Image @import prism.Prism.AWSAccount @import prism.RecipeUsage @import views.html.helper.CSRF @( recipe: Recipe, recentBakes: Iterable[Bake], recentCopies: Map[AmiId, Seq[Image]], accounts: Seq[AWSAccount], usage: prism.RecipeUsage, allRoles: Seq[RoleSummary], debugAvailable: Boolean, cloneForm: Form[_] )(implicit request: RequestHeader, flash: Flash, messages: play.api.i18n.Messages) @implicitFieldConstructor = @{ b3.inline.fieldConstructor() } @simpleLayout("AMIgo"){ <h1>@recipe.id.value</h1> <div class="panel panel-default"> <div class="panel-heading">Actions</div> <div class="panel-body"> <div class="btn-toolbar"> @b3.form(routes.BakeController.startBaking(recipe.id)) { @CSRF.formField <button class="post btn btn-primary">Bake!</button> } <a href="@routes.RecipeController.editRecipe(recipe.id)" class="btn btn-default">Edit</a> @if(debugAvailable){ @b3.form(routes.BakeController.startBaking(recipe.id, debug = true)) { @CSRF.formField <button class="post btn btn-warning mr-1">Bake with debug enabled</button> } } <a href="@routes.RecipeController.deleteConfirm(recipe.id)" class="btn btn-danger">Delete...</a> </div> </div> <div class="panel-body"> @b3.form(routes.RecipeController.cloneRecipe(recipe.id)) { @CSRF.formField @b3.inputWrapped( "newId", cloneForm("newId"), Symbol("placeholder") -> s"${recipe.id.value}-cloned" ) { input => <div class="input-group"> @input <span class="input-group-btn"> <button type="submit" class="btn btn-default">Clone</button> </span> </div> } } </div> </div> <div class="panel panel-default"> <div class="panel-heading">Description</div> <div class="panel-body"> <p>Created @fragments.timestamp(recipe.createdAt, recipe.createdBy)</p> <p>Modified @fragments.timestamp(recipe.modifiedAt, recipe.modifiedBy)</p> <p>Build schedule: <code>@recipe.bakeSchedule.map(_.quartzCronExpression).getOrElse("(none)")</code></p> <p>Request encrypted copy: @if(recipe.encryptFor.nonEmpty){ @recipe.encryptFor.map(_.accountNumber).mkString(", ") }else{ None }</p> <p>@recipe.description</p> @if(usage.instances.size + usage.launchConfigurations.size > 0) { <p>This recipe is used by <a href="@routes.RecipeController.showUsages(recipe.id)">@usage.instances.size instance@if(usage.instances.size != 1){s} and @usage.launchConfigurations.size launch configuration@if(usage.launchConfigurations.size != 1){s}</a></p> } else { <p><b>This recipe is not used</b></p> } <p> <a href="@(s"https://github.com/search?q=${helper.urlEncode(s"""org:guardian "${recipe.id}" NOT is:archived""")}&type=code")"> Search GitHub for usage </a> </p> <p class="@BaseImage.eolStatusClass(recipe.baseImage)">@BaseImage.eolStatusString(recipe.baseImage)</p> </div> </div> <div class="panel panel-default"> <div class="panel-heading">Base image</div> <div class="panel-body"> <a href="@routes.BaseImageController.showBaseImage(recipe.baseImage.id)">@recipe.baseImage.id</a> @recipe.diskSize.map{size=> With a disk size of @size gb. } </div> </div> <div class="panel panel-default"> <div class="panel-heading">Roles</div> <div class="panel-body"> @fragments.customisedRoles(Roles.customisedTransitiveDependency(allRoles, recipe.roles)) <h4>Inherited from base image @recipe.baseImage.id</h4> @fragments.customisedRoles(Roles.customisedTransitiveDependency(allRoles, recipe.baseImage.builtinRoles)) </div> </div> <div class="panel panel-default"> <div class="panel-heading">Recent bakes</div> <div class="panel-body"> <table class="table table-striped table-hover"> <thead> <th>Started</th> <th>Build number</th> @if(recentCopies.nonEmpty) { <th>Encrypted copy</th> } <th>Status</th> <th>AMI</th> @* Column for copy button *@ <th></th> <th>Usages</th> <th>AMIable</th> </thead> <tbody> @for(bake <- recentBakes) { <tr> <td class="has-block-link"> <a class="block-link" href="@routes.BakeController.showBake(bake.recipe.id, bake.buildNumber)"> @fragments.timestamp(bake.startedAt, bake.startedBy) </a> </td> <td class="has-block-link"> <a class="block-link" href="@routes.BakeController.showBake(bake.recipe.id, bake.buildNumber)"> @bake.buildNumber </a> </td> @if(recentCopies.nonEmpty) { <td class="has-block-link"></td> } <td class="has-block-link"> <a class="block-link" href="@routes.BakeController.showBake(bake.recipe.id, bake.buildNumber)"> @bake.status </a> </td> @if(bake.amiId.isDefined) { <td class="has-block-link"> <a class="block-link" href="@routes.BakeController.showBake(bake.recipe.id, bake.buildNumber)"> <code>@bake.amiId</code> </a> </td> <td class="absolute-container has-block-link"> <button class="btn btn-primary btn-xs absolute-right copy-button" title="Copy to clipboard" data-clipboard-text="@bake.amiId"> <img src="@routes.Assets.versioned("images/clippy.svg")" width="13" alt="Copy to clipboard" title="Copy to clipboard"> </button> </td> @fragments.usagesColumn(recipe, RecipeUsage.amiUsages(usage, bake.amiId.get)) <td> <a href="https://amiable.gutools.co.uk/ami?imageId=@bake.amiId" target="_blank" rel="noopener noreferrer"> <img src="@routes.Assets.versioned("images/amiable.png")" width="13" alt="View in AMIable" title="View in AMIable"> </a> </td> </td> } else { <td></td> <td></td> <td></td> <td></td> } </tr> @for(copy <- bake.amiId.flatMap(id => recentCopies.get(id)).getOrElse(Nil)){ <tr> <td>&nbsp;</td> <td>&nbsp;</td> <td> <ul class="list-unstyled"> <li>@defining(accounts.find(_.accountNumber == copy.ownerId)){ maybeOwnerAcc => @maybeOwnerAcc.map{ ownerAcc => @ownerAcc.accountName (@ownerAcc.accountNumber) }.getOrElse(copy.ownerId) } </li> @copy.encrypted.map{e => <li>Encrypted tag: @e</li>} </ul> </td> <td> @copy.state.capitalize </td> <td> <code>@copy.imageId</code> </td> <td class="absolute-container"> <button class="btn btn-primary btn-xs absolute-right copy-button" title="Copy to clipboard" data-clipboard-text="@copy.imageId"> <img src="@routes.Assets.versioned("images/clippy.svg")" width="13" alt="Copy to clipboard" title="copy to clipboard"> </button> </td> @fragments.usagesColumn(recipe, RecipeUsage.amiUsages(usage, copy.imageId)) <td> <a href="https://amiable.gutools.co.uk/ami?imageId=@copy.imageId" target="_blank" rel="noopener noreferrer"> <img src="@routes.Assets.versioned("images/amiable.png")" width="13" alt="View in AMIable" title="View in AMIable"> </a> </td> </tr> } } </tbody> </table> </div> </div> <script src="@routes.Assets.versioned("javascripts/clipboard.min.js")"></script> <script> var clipboard = new Clipboard('.copy-button'); clipboard.on('success', function(e) { console.log(e); e.trigger.classList.add('btn--success'); }); clipboard.on('error', function(e) { console.log(e); //TODO: Add tooltip }); </script> <!-- TODO listen to bake events and update the bakes list accordingly --> }