From 8909765bfb1b8007548d324627622192b4385190 Mon Sep 17 00:00:00 2001 From: Laura Frank Date: Wed, 15 Jul 2015 08:56:33 -0500 Subject: [PATCH] Adding imagelayers links to all application and service views --- app/assets/images/icon_image_layers.svg | 9 ++- .../panamax/application_dashboard.css.scss | 36 ++++++------ .../stylesheets/panamax/images.css.scss | 56 ++++++++++++------- .../stylesheets/panamax/manage.css.scss | 29 +++++++++- .../stylesheets/panamax/search.css.scss.erb | 13 +---- .../stylesheets/panamax/service_details.scss | 8 ++- app/models/app.rb | 12 +++- app/models/base_image.rb | 18 ------ app/models/local_image.rb | 5 ++ app/models/remote_image.rb | 17 ++++++ app/models/service.rb | 4 ++ app/presenters/json_service_row_presenter.rb | 4 ++ app/presenters/service_row_presenter.rb | 2 +- .../apps/_application_service_row.html.haml | 5 ++ app/views/apps/index.html.haml | 9 ++- app/views/apps/show.html.haml | 5 +- app/views/search/_image_row.html.haml | 2 +- app/views/search/_modal_image_row.html.haml | 2 +- app/views/services/show.html.haml | 1 + spec/models/image_spec.rb | 10 ---- spec/models/local_image_spec.rb | 16 +----- spec/models/remote_image_spec.rb | 6 ++ .../fixtures/service_representation_3.json | 1 + .../fixtures/service_representation_4.json | 1 + .../fixtures/service_representation_5.json | 1 + .../fixtures/services_representation.json | 1 + 26 files changed, 168 insertions(+), 105 deletions(-) diff --git a/app/assets/images/icon_image_layers.svg b/app/assets/images/icon_image_layers.svg index ea87ec36..54c39377 100644 --- a/app/assets/images/icon_image_layers.svg +++ b/app/assets/images/icon_image_layers.svg @@ -1 +1,8 @@ - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/app/assets/stylesheets/panamax/application_dashboard.css.scss b/app/assets/stylesheets/panamax/application_dashboard.css.scss index 1f668128..1e0f91de 100644 --- a/app/assets/stylesheets/panamax/application_dashboard.css.scss +++ b/app/assets/stylesheets/panamax/application_dashboard.css.scss @@ -19,31 +19,21 @@ section.applications { border-bottom: 1px solid $light_grey; width: 100%; height: 75px; - color: $grey; - &:hover { - color: $dark_grey; - - .actions{ - div { - display: block; - } - } - } + color: $dark_grey; > div { display: table-cell; } } + .name, .info { + vertical-align: middle; + } .name { font-size: 0.8em; - vertical-align: middle; - - * { - vertical-align: middle; - } a { + vertical-align: middle; font-size: 2.2em; text-decoration: none; @@ -52,10 +42,15 @@ section.applications { color: $blue_grey_dark; } } + } - b { - font-size: 2.2em; - margin: 0 5px 0 20px; + .info { + > a { + margin: 0 8px 0 10px; + } + span { + display: inline-block; + margin-top: 3px; } } @@ -74,10 +69,13 @@ header.application { h1.breadcrumbs { display: inline-block; - width: 900px; border-bottom: none; margin-bottom: 0; padding-bottom: 0; + + .imagelayers-link { + display: inline-block; + float: none; + } } } diff --git a/app/assets/stylesheets/panamax/images.css.scss b/app/assets/stylesheets/panamax/images.css.scss index 98b12359..bb236b6b 100644 --- a/app/assets/stylesheets/panamax/images.css.scss +++ b/app/assets/stylesheets/panamax/images.css.scss @@ -6,9 +6,7 @@ h1 { margin-bottom: 0; } -} -#images_flow { .select-all { margin-top: 30px; float: right; @@ -62,27 +60,45 @@ } } -ul.images { - clear: both; -} - -ul.images li { - border-bottom: $light_grey 1px solid; - overflow: auto; - padding-bottom: 22px; - padding-top: 22px; +.imagelayers-link { + background: image-url('icon_image_layers.svg') -10px -17px no-repeat; + background-size: 40px 60px; + float: left; + width: 20px; + height: 20px; + @include hide-text; - .imagelayers-link { - background: image-url('icon_image_layers.svg') -10px -17px; - background-size: 40px 40px; - float: left; - width: 20px; + &:hover { + background-position: -10px 3px; + } +} +.imagelayers-link-with-text { + position: relative; + padding-left: 26px; + &:after { + content: ''; height: 20px; - @include hide-text; + width: 20px; + display: block; + position: absolute; + top: 0; + left: 0; + background: image-url('icon_image_layers.svg') 0 -19px no-repeat; + background-size: 20px 60px; + } - &:hover { - background-position: -10px 3px; - } + &:hover:after { + background-position: 0 1px; + } +} + +ul.images { + clear: both; + li { + border-bottom: $light_grey 1px solid; + overflow: auto; + padding-bottom: 22px; + padding-top: 22px; } h3 { diff --git a/app/assets/stylesheets/panamax/manage.css.scss b/app/assets/stylesheets/panamax/manage.css.scss index 471abbfe..c7266999 100644 --- a/app/assets/stylesheets/panamax/manage.css.scss +++ b/app/assets/stylesheets/panamax/manage.css.scss @@ -203,6 +203,29 @@ height: 20px; } } + .imagelayers-action { + position: relative; + text-indent: -9999px; + color: transparent; + float: left; + height: 40px; + width: 20px; + &:after { + content: ''; + height: 18px; + width: 20px; + display: block; + position: absolute; + top: 13px; + left: -1px; + background: image-url('icon_image_layers.svg') -2px -34px no-repeat; + background-size: 20px 50px; + } + + &:hover:after { + background-position: -2px 1px; + } + } } } } @@ -354,6 +377,10 @@ section.deployment-details { span.application-access { position: relative; text-decoration: underline; + display: inline-block; + padding-right: 10px; + border-right: 1px solid #aaa; + margin-right: 8px; &:hover { cursor: pointer; @@ -544,7 +571,7 @@ section.application-services { background-color: $white; color: $blue_grey_dark; > a { - width: 195px; + width: 167px; } .actions { display: inline-block; diff --git a/app/assets/stylesheets/panamax/search.css.scss.erb b/app/assets/stylesheets/panamax/search.css.scss.erb index 33c97441..7c09d6bb 100644 --- a/app/assets/stylesheets/panamax/search.css.scss.erb +++ b/app/assets/stylesheets/panamax/search.css.scss.erb @@ -203,17 +203,8 @@ body#search_flow main:after { font-size: 0.8em; line-height: 1.2; } - - .imagelayers { - height: 40px; - width: 40px; - text-indent: -9999px; - color: transparent; - background: image-url('icon_image_layers.svg') -10px -17px no-repeat; - background-size: 40px 40px; - &:hover { - background-position: -10px 3px; - } + .imagelayers-link { + margin-right: 6px; } } diff --git a/app/assets/stylesheets/panamax/service_details.scss b/app/assets/stylesheets/panamax/service_details.scss index d6d45d1f..42c9e79e 100644 --- a/app/assets/stylesheets/panamax/service_details.scss +++ b/app/assets/stylesheets/panamax/service_details.scss @@ -208,8 +208,12 @@ font-size: 0.9em; padding-right: 5px; &:last-child { - padding-left: 10px; - border-left: 1px solid $dark_grey; + padding-left: 36px; + border-left: 1px solid #AAAAAA; + &:after { + top: -2px; + left: 11px; + } } } } diff --git a/app/models/app.rb b/app/models/app.rb index 9d7788a7..3e5e037f 100644 --- a/app/models/app.rb +++ b/app/models/app.rb @@ -28,7 +28,17 @@ def has_empty_env_values? end def service_count_label - 'Service'.pluralize(services.length) + 'service'.pluralize(services.length) + end + + def imagelayers_url + service_string = '' + + services.each do |service| + service_string << "#{service.from}," + end + + "#{IMAGELAYERS_BASE_URL}?images=#{service_string.chop}" end def find_service_by_name(name) diff --git a/app/models/base_image.rb b/app/models/base_image.rb index 0ba772d2..e8a00460 100644 --- a/app/models/base_image.rb +++ b/app/models/base_image.rb @@ -32,22 +32,6 @@ def badge_class status_label.downcase end - def docker_index_url - if remote? - path_part = (source =~ /\//) ? "u/#{source}" : "_/#{source}" - "#{DOCKER_INDEX_BASE_URL}#{path_part}" - end - end - - def imagelayers_url - if remote? - "#{IMAGELAYERS_BASE_URL}?images=#{source}" - else - image_name = self.tags.first.split(':').first - "#{IMAGELAYERS_BASE_URL}?images=#{image_name}" - end - end - def short_description truncate(description, length: 165, escape: false, separator: ' ') end @@ -57,8 +41,6 @@ def as_json(options={}) .merge( 'status_label' => status_label, 'short_description' => short_description, - 'docker_index_url' => docker_index_url, - 'imagelayers_url' => imagelayers_url, 'badge_class' => badge_class ) end diff --git a/app/models/local_image.rb b/app/models/local_image.rb index e9d16c51..53a454e6 100644 --- a/app/models/local_image.rb +++ b/app/models/local_image.rb @@ -13,6 +13,11 @@ def name tags.first end + def imagelayers_url + image_name = self.tags.first.split(':').first + "#{IMAGELAYERS_BASE_URL}?images=#{image_name}" + end + def self.batch_destroy(image_ids) count = 0 failed = image_ids.each_with_object(Set.new) do |id, fail_list| diff --git a/app/models/remote_image.rb b/app/models/remote_image.rb index 6ae0b1ca..99799e27 100644 --- a/app/models/remote_image.rb +++ b/app/models/remote_image.rb @@ -2,4 +2,21 @@ class RemoteImage < BaseImage def remote? true end + + def docker_index_url + path_part = (source =~ /\//) ? "u/#{source}" : "_/#{source}" + "#{DOCKER_INDEX_BASE_URL}#{path_part}" + end + + def imagelayers_url + "#{IMAGELAYERS_BASE_URL}?images=#{source}" + end + + def as_json(options={}) + super + .merge( + 'docker_index_url' => docker_index_url, + 'imagelayers_url' => imagelayers_url + ) + end end diff --git a/app/models/service.rb b/app/models/service.rb index 2a34027d..7d0d0ce0 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -121,6 +121,10 @@ def docker_search_url "#{DOCKER_INDEX_BASE_URL}search?q=#{self.base_image_name}" end + def imagelayers_url + "#{IMAGELAYERS_BASE_URL}images?=#{self.base_image_name}:#{self.image_tag_name}" + end + def as_json(options={}) super.merge('status' => status) end diff --git a/app/presenters/json_service_row_presenter.rb b/app/presenters/json_service_row_presenter.rb index ee24d18c..7291934c 100644 --- a/app/presenters/json_service_row_presenter.rb +++ b/app/presenters/json_service_row_presenter.rb @@ -11,6 +11,10 @@ def service_url '{{service_url}}' end + def imagelayers_url + '{{imagelayers_url}}' + end + def status '{{status}}' end diff --git a/app/presenters/service_row_presenter.rb b/app/presenters/service_row_presenter.rb index 0c827c72..fd5048a4 100644 --- a/app/presenters/service_row_presenter.rb +++ b/app/presenters/service_row_presenter.rb @@ -1,6 +1,6 @@ class ServiceRowPresenter - delegate :id, :icon, :name, :status, to: :@service + delegate :id, :icon, :name, :status, :imagelayers_url, to: :@service def initialize(service) @service = service diff --git a/app/views/apps/_application_service_row.html.haml b/app/views/apps/_application_service_row.html.haml index 82261e94..2e972217 100644 --- a/app/views/apps/_application_service_row.html.haml +++ b/app/views/apps/_application_service_row.html.haml @@ -5,6 +5,11 @@ presenter.service_url, title: 'service-details' .actions + = link_to presenter.name, + presenter.imagelayers_url, + class: 'imagelayers-action', + target: '_blank', + title: 'Inspect this application on imagelayers.io' = link_to 'view', presenter.service_url, class: 'edit-action', diff --git a/app/views/apps/index.html.haml b/app/views/apps/index.html.haml index 58169e32..9a76e96e 100644 --- a/app/views/apps/index.html.haml +++ b/app/views/apps/index.html.haml @@ -9,8 +9,13 @@ %div.application .name = link_to app.name, app_path(app.id) - %b= app.services.length - %span= app.service_count_label + .info + = link_to app.name, app.imagelayers_url, target: '_blank', title: 'View this application on imagelayers.io', class: 'imagelayers-link' + %span + %b + = app.services.length + = app.service_count_label + .actions = render 'application_button_menu', app: app diff --git a/app/views/apps/show.html.haml b/app/views/apps/show.html.haml index e3b74971..bd4392a6 100644 --- a/app/views/apps/show.html.haml +++ b/app/views/apps/show.html.haml @@ -11,8 +11,8 @@ %header.application = render '/shared/breadcrumbs', breadcrumbs: ['Manage', link_to('Dashboard', dashboard_index_path), - link_to('Applications', apps_path), yield(:title)] - + link_to('Applications', apps_path), + yield(:title)] %section.deployment-details %ul.deployment-env %li @@ -32,6 +32,7 @@ %p = succeed '.' do %a{href:'https://github.com/CenturyLinkLabs/panamax-ui/wiki/How-To%3A-Port-Forwarding-on-VirtualBox'}Go to our wiki for instructions + = link_to("View #{@app.name} on imagelayers.io", @app.imagelayers_url, title: "View #{@app.name} on imagelayers.io", target: '_blank', class:'imagelayers-link-with-text') = render 'application_button_menu', app: @app diff --git a/app/views/search/_image_row.html.haml b/app/views/search/_image_row.html.haml index 37e1a0b2..0b3b8f76 100644 --- a/app/views/search/_image_row.html.haml +++ b/app/views/search/_image_row.html.haml @@ -6,7 +6,7 @@ %h3 - if remote = link_to presenter.title, presenter.docker_index_url, target: '_blank', title: 'View details on the Docker Hub', class: 'docker-hub' - = link_to presenter.title, presenter.imagelayers_url, target: '_blank', title: 'Inspect this image on imagelayers.io', class: 'imagelayers' + = link_to presenter.title, presenter.imagelayers_url, target: '_blank', title: 'Inspect this image on imagelayers.io', class: 'imagelayers-link' - else = presenter.title %p= presenter.short_description diff --git a/app/views/search/_modal_image_row.html.haml b/app/views/search/_modal_image_row.html.haml index f68288d7..239ba3e5 100644 --- a/app/views/search/_modal_image_row.html.haml +++ b/app/views/search/_modal_image_row.html.haml @@ -5,7 +5,7 @@ %h3 - if remote = link_to presenter.title, presenter.docker_index_url, target: '_blank', title: 'View details on the Docker Hub', class: 'docker-hub' - = link_to presenter.title, presenter.imagelayers_url, target: '_blank', title: 'Inspect this image on imagelayers.io', class: 'imagelayers' + = link_to presenter.title, presenter.imagelayers_url, target: '_blank', title: 'Inspect this image on imagelayers.io', class: 'imagelayers-link' - else = presenter.title %p= presenter.short_description diff --git a/app/views/services/show.html.haml b/app/views/services/show.html.haml index 3ee1ab06..60c9850c 100644 --- a/app/views/services/show.html.haml +++ b/app/views/services/show.html.haml @@ -42,6 +42,7 @@ .documentation = link_to('Documentation', '#', { class: 'instructions-dialog', data: {'doc-url'=> documentation_app_path(@app.id)} }) if @app.documentation_to_html.present? = link_to 'Find on Docker Hub', @service.docker_search_url, { target: 'blank', data: { 'tracking-method' => 'click', 'tracking-action' => 'Find on Docker Hub', 'tracking-category' => 'Outbound Link', 'tracking-label' => @service.docker_search_url }} + = link_to "View #{@service.base_image_name} on imagelayers.io", @service.imagelayers_url, title: "View #{@service.base_image_name} on imagelayers.io", class: 'imagelayers-link-with-text', target: '_blank', data: { 'tracking-method' => 'click', 'tracking-action' => 'View on Imagelayers', 'tracking-category' => 'Outbound Link', 'tracking-label' => @service.imagelayers_url } = form_for [@app, @service], html: { class: 'service-edit-form' } do |f| = render 'shared/errors', errors: f.object.errors diff --git a/spec/models/image_spec.rb b/spec/models/image_spec.rb index 502bfb35..95a77f31 100644 --- a/spec/models/image_spec.rb +++ b/spec/models/image_spec.rb @@ -66,16 +66,6 @@ end end - describe '#docker_index_url' do - before do - subject.source = 'ctl/booyah:latest' - end - - it 'returns the url' do - expect(subject.docker_index_url).to eq 'https://registry.hub.docker.com/u/ctl/booyah' - end - end - describe '#base_image_name' do let(:docker_image_name) { double(:docker_image_name, base_image: 'fooyah') } diff --git a/spec/models/local_image_spec.rb b/spec/models/local_image_spec.rb index d506ce70..3565c295 100644 --- a/spec/models/local_image_spec.rb +++ b/spec/models/local_image_spec.rb @@ -52,18 +52,6 @@ end end - describe '#imagelayers_url' do - it 'concatenates the imagelayers URL with the image name' do - expect(subject.imagelayers_url).to eq "#{IMAGELAYERS_URL}?images=blah/not-panamax" - end - end - - describe '#docker_index_url' do - it 'is nil' do - expect(subject.docker_index_url).to be_nil - end - end - describe '.batch_destroy' do describe 'when successful' do let(:fake_image) { double(:fake_image, id: 1, destroy: true) } @@ -123,9 +111,7 @@ expected = attributes.merge( 'short_description' => 'this thing goes boom shaka laka', 'status_label' => 'Local', - 'badge_class' => 'local', - 'docker_index_url' => nil, - 'imagelayers_url' => "#{IMAGELAYERS_URL}?images=blah/not-panamax" + 'badge_class' => 'local' ) expect(subject.as_json).to eq expected end diff --git a/spec/models/remote_image_spec.rb b/spec/models/remote_image_spec.rb index cda2626b..f4a0f142 100644 --- a/spec/models/remote_image_spec.rb +++ b/spec/models/remote_image_spec.rb @@ -42,6 +42,12 @@ end end + describe '#imagelayers_url' do + it 'concatenates the imagelayers URL with the image name' do + expect(subject.imagelayers_url).to eq "#{IMAGELAYERS_URL}?images=boom/shaka" + end + end + describe '#status_label' do it 'returns the registry name' do subject.registry_name = 'private reg' diff --git a/spec/support/fixtures/service_representation_3.json b/spec/support/fixtures/service_representation_3.json index ec5460f2..19f581ff 100644 --- a/spec/support/fixtures/service_representation_3.json +++ b/spec/support/fixtures/service_representation_3.json @@ -1,6 +1,7 @@ { "id":"3", "name":"blah", + "from": "foo/blah:latest", "categories":[{"name":"foo"},{"name":"baz"}], "sub_state": "running", "ports":[{"host_port":8080,"container_port":80}] diff --git a/spec/support/fixtures/service_representation_4.json b/spec/support/fixtures/service_representation_4.json index 0dadc9c7..fd499842 100644 --- a/spec/support/fixtures/service_representation_4.json +++ b/spec/support/fixtures/service_representation_4.json @@ -1,6 +1,7 @@ { "id":"4", "name":"barf", + "from": "foo/barf:latest", "categories":[{"name":"foo"}], "sub_state": null, "ports": [] diff --git a/spec/support/fixtures/service_representation_5.json b/spec/support/fixtures/service_representation_5.json index bc682b27..bf55aeac 100644 --- a/spec/support/fixtures/service_representation_5.json +++ b/spec/support/fixtures/service_representation_5.json @@ -1,6 +1,7 @@ { "id":"5", "name":"bark", + "from": "foo/bark:latest", "categories":[{"name":"bar"}], "sub_state": null, "ports": [] diff --git a/spec/support/fixtures/services_representation.json b/spec/support/fixtures/services_representation.json index 575a5e41..61ca2705 100644 --- a/spec/support/fixtures/services_representation.json +++ b/spec/support/fixtures/services_representation.json @@ -2,6 +2,7 @@ { "id": 1, "name": "tutum_wordpress_1", + "from": "tutum/wordpress", "errors": null, "categories": [ {