diff options
26 files changed, 261 insertions, 79 deletions
diff --git a/app/assets/javascripts/merged_buttons.js b/app/assets/javascripts/merged_buttons.js index 9548a98f499..7b0997c6520 100644 --- a/app/assets/javascripts/merged_buttons.js +++ b/app/assets/javascripts/merged_buttons.js @@ -1,11 +1,13 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len */ -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +import '~/lib/utils/url_utility'; +(function() { this.MergedButtons = (function() { function MergedButtons() { - this.removeSourceBranch = bind(this.removeSourceBranch, this); + this.removeSourceBranch = this.removeSourceBranch.bind(this); + this.removeBranchSuccess = this.removeBranchSuccess.bind(this); + this.removeBranchError = this.removeBranchError.bind(this); this.$removeBranchWidget = $('.remove_source_branch_widget'); this.$removeBranchProgress = $('.remove_source_branch_in_progress'); this.$removeBranchFailed = $('.remove_source_branch_widget.failed'); @@ -22,7 +24,7 @@ MergedButtons.prototype.initEventListeners = function() { $(document).on('click', '.remove_source_branch', this.removeSourceBranch); $(document).on('ajax:success', '.remove_source_branch', this.removeBranchSuccess); - return $(document).on('ajax:error', '.remove_source_branch', this.removeBranchError); + $(document).on('ajax:error', '.remove_source_branch', this.removeBranchError); }; MergedButtons.prototype.removeSourceBranch = function() { @@ -31,7 +33,7 @@ }; MergedButtons.prototype.removeBranchSuccess = function() { - return location.reload(); + gl.utils.refreshCurrentPage(); }; MergedButtons.prototype.removeBranchError = function() { diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index c241816788b..664539e93e1 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -158,6 +158,7 @@ li.task-list-item { list-style-type: none; position: relative; + min-height: 22px; padding-left: 28px; margin-left: 0 !important; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 712eb7caf33..20ef9a774e4 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -26,6 +26,7 @@ $gray-dark: darken($gray-light, $darken-dark-factor); $gray-darker: #eee; $gray-darkest: #c4c4c4; +$green-25: #f6fcf8; $green-50: #e4f5eb; $green-100: #bae6cc; $green-200: #8dd5aa; @@ -37,6 +38,7 @@ $green-700: #12753a; $green-800: #0e5a2d; $green-900: #0a4020; +$blue-25: #f6fafd; $blue-50: #e4eff9; $blue-100: #bcd7f1; $blue-200: #8fbce8; @@ -48,6 +50,7 @@ $blue-700: #17599c; $blue-800: #134a81; $blue-900: #0f3b66; +$orange-25: #fffcf8; $orange-50: #fff2e1; $orange-100: #fedfb3; $orange-200: #feca81; @@ -59,6 +62,7 @@ $orange-700: #c26700; $orange-800: #a35100; $orange-900: #853b00; +$red-25: #fef7f6; $red-50: #fbe7e4; $red-100: #f4c4bc; $red-200: #ed9d90; @@ -147,7 +151,7 @@ $gl-sidebar-padding: 22px; /* * Misc */ -$row-hover: lighten($blue-50, 2%); +$row-hover: $blue-25; $row-hover-border: $blue-100; $progress-color: #c0392b; $header-height: 50px; @@ -223,18 +227,18 @@ $gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background; /* * Commit Diff Colors */ -$added: $green-300; -$deleted: $red-300; -$line-added: $green-50; -$line-added-dark: $green-100; -$line-removed: $red-50; -$line-removed-dark: $red-100; -$line-number-old: lighten($red-100, 5%); -$line-number-new: lighten($green-100, 5%); -$line-number-select: lighten($orange-100, 5%); -$line-target-blue: $blue-50; -$line-select-yellow: $orange-50; -$line-select-yellow-dark: $orange-100; +$added: #63c363; +$deleted: #f77; +$line-added: #ecfdf0; +$line-added-dark: #c7f0d2; +$line-removed: #fbe9eb; +$line-removed-dark: #fac5cd; +$line-number-old: #f9d7dc; +$line-number-new: #ddfbe6; +$line-number-select: #fbf2da; +$line-target-blue: #f6faff; +$line-select-yellow: #fcf8e7; +$line-select-yellow-dark: #f0e2bd; $dark-diff-match-bg: rgba(255, 255, 255, 0.3); $dark-diff-match-color: rgba(255, 255, 255, 0.1); $file-mode-changed: #777; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index ad0f2f6efbb..c78fb8ede79 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -627,7 +627,6 @@ ul.notes { } &:not(.is-disabled):hover, - &:not(.is-disabled):focus, &.is-active { color: $gl-text-green; @@ -641,6 +640,11 @@ ul.notes { height: 15px; width: 15px; } + + .loading { + margin: 0; + height: auto; + } } .discussion-next-btn { diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 82f4182d59a..d0c94d3b694 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -20,7 +20,8 @@ class ContainerRepository < ActiveRecord::Base end def path - @path ||= [project.full_path, name].select(&:present?).join('/') + @path ||= [project.full_path, name] + .select(&:present?).join('/').downcase end def location diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml index 6a5986f496a..50132572096 100644 --- a/app/views/admin/services/index.html.haml +++ b/app/views/admin/services/index.html.haml @@ -13,7 +13,7 @@ - @services.sort_by(&:title).each do |service| %tr %td - = icon("copy", class: 'clgray') + = boolean_to_icon service.activated? %td = link_to edit_admin_application_settings_service_path(service.id) do %strong= service.title diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index c12c05eeb73..1f021ad77e5 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -52,11 +52,10 @@ ":aria-label" => "buttonText", "@click" => "resolve", ":title" => "buttonText", - "v-show" => "!loading", ":ref" => "'button'" } - = icon("spin spinner", "v-show" => "loading") - = render "shared/icons/icon_status_success.svg" + = icon("spin spinner", "v-show" => "loading", class: 'loading') + %div{ 'v-show' => '!loading' }= render "shared/icons/icon_status_success.svg" - if current_user - if note.emoji_awardable? diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml index 7a7e3d46796..c229d18903f 100644 --- a/app/views/shared/empty_states/_issues.html.haml +++ b/app/views/shared/empty_states/_issues.html.haml @@ -16,6 +16,8 @@ Also, issues are searchable and filterable. - if project_select_button = render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue' + = link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link' - else - %h4 There are no issues to show. - = link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link' + .text-center + %h4 There are no issues to show. + = link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link' diff --git a/changelogs/unreleased/empty-task-list-alignment.yml b/changelogs/unreleased/empty-task-list-alignment.yml new file mode 100644 index 00000000000..ca04e1cab5a --- /dev/null +++ b/changelogs/unreleased/empty-task-list-alignment.yml @@ -0,0 +1,4 @@ +--- +title: Fixed alignment of empty task list items +merge_request: +author: diff --git a/changelogs/unreleased/fix-trace-seeking.yml b/changelogs/unreleased/fix-trace-seeking.yml new file mode 100644 index 00000000000..b753df4bb43 --- /dev/null +++ b/changelogs/unreleased/fix-trace-seeking.yml @@ -0,0 +1,4 @@ +--- +title: Fix invalid encoding when showing some traces +merge_request: 10681 +author: diff --git a/changelogs/unreleased/issues-empty-state-not-centered.yml b/changelogs/unreleased/issues-empty-state-not-centered.yml new file mode 100644 index 00000000000..883125e28b1 --- /dev/null +++ b/changelogs/unreleased/issues-empty-state-not-centered.yml @@ -0,0 +1,4 @@ +--- +title: Centered issues empty state +merge_request: +author: diff --git a/changelogs/unreleased/pms-lighter-colors.yml b/changelogs/unreleased/pms-lighter-colors.yml new file mode 100644 index 00000000000..958d4bc0ac0 --- /dev/null +++ b/changelogs/unreleased/pms-lighter-colors.yml @@ -0,0 +1,4 @@ +--- +title: Add lighter colors and fix existing light colors +merge_request: 10690 +author: diff --git a/doc/update/README.md b/doc/update/README.md index 7921d03d611..d024a809f24 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -50,20 +50,17 @@ update them are in [a separate document][omnidocker]. ## Upgrading without downtime -Starting with GitLab 9.1.0 it's possible to upgrade to a newer version of GitLab +Starting with GitLab 9.1.0 it's possible to upgrade to a newer major, minor, or patch version of GitLab without having to take your GitLab instance offline. However, for this to work there are the following requirements: -1. You can only upgrade 1 release at a time. For example, if 9.1.15 is the last - release of 9.1 then you can safely upgrade from that version to 9.2.0. +1. You can only upgrade 1 minor release at a time. So from 9.1 to 9.2, not to 9.3. +2. You have to be on the most recent patch release. For example, if 9.1.15 is the last + release of 9.1 then you can safely upgrade from that version to any 9.2.x version. However, if you are running 9.1.14 you first need to upgrade to 9.1.15. 2. You have to use [post-deployment migrations](../development/post_deployment_migrations.md). -3. You are using PostgreSQL. If you are using MySQL you will still need downtime - when upgrading. - -This applies to major, minor, and patch releases unless stated otherwise in a -release post. +3. You are using PostgreSQL. If you are using MySQL please look at the release post to see if downtime is required. ## Upgrading between editions diff --git a/lib/banzai/filter/issuable_state_filter.rb b/lib/banzai/filter/issuable_state_filter.rb index 6b78aa795b4..0b2b8bd7f4d 100644 --- a/lib/banzai/filter/issuable_state_filter.rb +++ b/lib/banzai/filter/issuable_state_filter.rb @@ -13,8 +13,8 @@ module Banzai issuables = extractor.extract([doc]) issuables.each do |node, issuable| - if VISIBLE_STATES.include?(issuable.state) - node.children.last.content += " [#{issuable.state}]" + if VISIBLE_STATES.include?(issuable.state) && node.children.present? + node.add_child(Nokogiri::XML::Text.new(" [#{issuable.state}]", doc)) end end diff --git a/lib/container_registry/path.rb b/lib/container_registry/path.rb index a4b5f2aba6c..4a585996aa5 100644 --- a/lib/container_registry/path.rb +++ b/lib/container_registry/path.rb @@ -15,7 +15,7 @@ module ContainerRegistry LEVELS_SUPPORTED = 3 def initialize(path) - @path = path + @path = path.to_s.downcase end def valid? @@ -25,7 +25,7 @@ module ContainerRegistry end def components - @components ||= @path.to_s.split('/') + @components ||= @path.split('/') end def nodes diff --git a/lib/gitlab/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb index 41dcf846fed..3b335cdfd01 100644 --- a/lib/gitlab/ci/trace/stream.rb +++ b/lib/gitlab/ci/trace/stream.rb @@ -25,11 +25,10 @@ module Gitlab end def limit(last_bytes = LIMIT_SIZE) - stream_size = size - if stream_size < last_bytes - last_bytes = stream_size + if last_bytes < size + stream.seek(-last_bytes, IO::SEEK_END) + stream.readline end - stream.seek(-last_bytes, IO::SEEK_END) end def append(data, offset) diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb index 88d28b649a4..0e23c3a8849 100644 --- a/spec/features/merge_requests/diff_notes_resolve_spec.rb +++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb @@ -198,6 +198,8 @@ feature 'Diff notes resolve', feature: true, js: true do it 'does not mark discussion as resolved when resolving single note' do page.first '.diff-content .note' do first('.line-resolve-btn').click + + expect(page).to have_selector('.note-action-button .loading') expect(first('.line-resolve-btn')['data-original-title']).to eq("Resolved by #{user.name}") end diff --git a/spec/fixtures/trace/ansi-sequence-and-unicode b/spec/fixtures/trace/ansi-sequence-and-unicode new file mode 100644 index 00000000000..5d2466f0d0f --- /dev/null +++ b/spec/fixtures/trace/ansi-sequence-and-unicode @@ -0,0 +1,5 @@ +[0m[01;34m.[0m +[30;42m..[0m +😺 +ヾ(´༎ຶД༎ຶ`)ノ +[01;32m許功蓋[0m diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index fddeaaf504d..47d904b865b 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -7,6 +7,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } + let(:merged_merge_request) { create(:merge_request, :merged, source_project: project, target_project: project) } let(:pipeline) do create( :ci_pipeline, @@ -32,6 +33,12 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont render_merge_request(example.description, merge_request) end + it 'merge_requests/merged_merge_request.html.raw' do |example| + allow_any_instance_of(MergeRequest).to receive(:source_branch_exists?).and_return(true) + allow_any_instance_of(MergeRequest).to receive(:can_remove_source_branch?).and_return(true) + render_merge_request(example.description, merged_merge_request) + end + private def render_merge_request(fixture_file_name, merge_request) diff --git a/spec/javascripts/merged_buttons_spec.js b/spec/javascripts/merged_buttons_spec.js new file mode 100644 index 00000000000..b5c5e60dd97 --- /dev/null +++ b/spec/javascripts/merged_buttons_spec.js @@ -0,0 +1,44 @@ +/* global MergedButtons */ + +import '~/merged_buttons'; + +describe('MergedButtons', () => { + const fixturesPath = 'merge_requests/merged_merge_request.html.raw'; + preloadFixtures(fixturesPath); + + beforeEach(() => { + loadFixtures(fixturesPath); + this.mergedButtons = new MergedButtons(); + this.$removeBranchWidget = $('.remove_source_branch_widget:not(.failed)'); + this.$removeBranchProgress = $('.remove_source_branch_in_progress'); + this.$removeBranchFailed = $('.remove_source_branch_widget.failed'); + this.$removeBranchButton = $('.remove_source_branch'); + }); + + describe('removeSourceBranch', () => { + it('shows loader', () => { + $('.remove_source_branch').trigger('click'); + expect(this.$removeBranchProgress).toBeVisible(); + expect(this.$removeBranchWidget).not.toBeVisible(); + }); + }); + + describe('removeBranchSuccess', () => { + it('refreshes page when branch removed', () => { + spyOn(gl.utils, 'refreshCurrentPage').and.stub(); + const response = { status: 200 }; + this.$removeBranchButton.trigger('ajax:success', response, 'xhr'); + expect(gl.utils.refreshCurrentPage).toHaveBeenCalled(); + }); + }); + + describe('removeBranchError', () => { + it('shows error message', () => { + const response = { status: 500 }; + this.$removeBranchButton.trigger('ajax:error', response, 'xhr'); + expect(this.$removeBranchFailed).toBeVisible(); + expect(this.$removeBranchProgress).not.toBeVisible(); + expect(this.$removeBranchWidget).not.toBeVisible(); + }); + }); +}); diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb index 603b79a323c..5cb98163746 100644 --- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb +++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb @@ -6,8 +6,8 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do let(:user) { create(:user) } - def create_link(data) - link_to('text', '', class: 'gfm has-tooltip', data: data) + def create_link(text, data) + link_to(text, '', class: 'gfm has-tooltip', data: data) end it 'ignores non-GFM links' do @@ -19,16 +19,37 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'ignores non-issuable links' do project = create(:empty_project, :public) - link = create_link(project: project, reference_type: 'issue') + link = create_link('text', project: project, reference_type: 'issue') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') end + it 'ignores issuable links with empty content' do + issue = create(:issue, :closed) + link = create_link('', issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: user) + + expect(doc.css('a').last.text).to eq('') + end + + it 'adds text with standard formatting' do + issue = create(:issue, :closed) + link = create_link( + 'something <strong>else</strong>'.html_safe, + issue: issue.id, + reference_type: 'issue' + ) + doc = filter(link, current_user: user) + + expect(doc.css('a').last.inner_html). + to eq('something <strong>else</strong> [closed]') + end + context 'for issue references' do it 'ignores open issue references' do issue = create(:issue) - link = create_link(issue: issue.id, reference_type: 'issue') + link = create_link('text', issue: issue.id, reference_type: 'issue') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') @@ -36,7 +57,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'ignores reopened issue references' do reopened_issue = create(:issue, :reopened) - link = create_link(issue: reopened_issue.id, reference_type: 'issue') + link = create_link('text', issue: reopened_issue.id, reference_type: 'issue') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') @@ -44,7 +65,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'appends [closed] to closed issue references' do closed_issue = create(:issue, :closed) - link = create_link(issue: closed_issue.id, reference_type: 'issue') + link = create_link('text', issue: closed_issue.id, reference_type: 'issue') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text [closed]') @@ -54,7 +75,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do context 'for merge request references' do it 'ignores open merge request references' do mr = create(:merge_request) - link = create_link(merge_request: mr.id, reference_type: 'merge_request') + link = create_link('text', merge_request: mr.id, reference_type: 'merge_request') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') @@ -62,7 +83,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'ignores reopened merge request references' do mr = create(:merge_request, :reopened) - link = create_link(merge_request: mr.id, reference_type: 'merge_request') + link = create_link('text', merge_request: mr.id, reference_type: 'merge_request') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') @@ -70,7 +91,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'ignores locked merge request references' do mr = create(:merge_request, :locked) - link = create_link(merge_request: mr.id, reference_type: 'merge_request') + link = create_link('text', merge_request: mr.id, reference_type: 'merge_request') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text') @@ -78,7 +99,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'appends [closed] to closed merge request references' do mr = create(:merge_request, :closed) - link = create_link(merge_request: mr.id, reference_type: 'merge_request') + link = create_link('text', merge_request: mr.id, reference_type: 'merge_request') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text [closed]') @@ -86,7 +107,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do it 'appends [merged] to merged merge request references' do mr = create(:merge_request, :merged) - link = create_link(merge_request: mr.id, reference_type: 'merge_request') + link = create_link('text', merge_request: mr.id, reference_type: 'merge_request') doc = filter(link, current_user: user) expect(doc.css('a').last.text).to eq('text [merged]') diff --git a/spec/lib/container_registry/path_spec.rb b/spec/lib/container_registry/path_spec.rb index b9c4572c269..f3b3a9a715f 100644 --- a/spec/lib/container_registry/path_spec.rb +++ b/spec/lib/container_registry/path_spec.rb @@ -33,10 +33,20 @@ describe ContainerRegistry::Path do end describe '#to_s' do - let(:path) { 'some/image' } + context 'when path does not have uppercase characters' do + let(:path) { 'some/image' } - it 'return a string with a repository path' do - expect(subject.to_s).to eq path + it 'return a string with a repository path' do + expect(subject.to_s).to eq 'some/image' + end + end + + context 'when path has uppercase characters' do + let(:path) { 'SoMe/ImAgE' } + + it 'return a string with a repository path' do + expect(subject.to_s).to eq 'some/image' + end end end @@ -70,6 +80,12 @@ describe ContainerRegistry::Path do it { is_expected.to be_valid } end + + context 'when path contains uppercase letters' do + let(:path) { 'Some/Registry' } + + it { is_expected.to be_valid } + end end describe '#has_repository?' do diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb index 2e57ccef182..9e3bd6d662f 100644 --- a/spec/lib/gitlab/ci/trace/stream_spec.rb +++ b/spec/lib/gitlab/ci/trace/stream_spec.rb @@ -17,12 +17,12 @@ describe Gitlab::Ci::Trace::Stream do describe '#limit' do let(:stream) do described_class.new do - StringIO.new("12345678") + StringIO.new((1..8).to_a.join("\n")) end end - it 'if size is larger we start from beggining' do - stream.limit(10) + it 'if size is larger we start from beginning' do + stream.limit(20) expect(stream.tell).to eq(0) end @@ -30,7 +30,27 @@ describe Gitlab::Ci::Trace::Stream do it 'if size is smaller we start from the end' do stream.limit(2) - expect(stream.tell).to eq(6) + expect(stream.raw).to eq("8") + end + + context 'when the trace contains ANSI sequence and Unicode' do + let(:stream) do + described_class.new do + File.open(expand_fixture_path('trace/ansi-sequence-and-unicode')) + end + end + + it 'forwards to the next linefeed, case 1' do + stream.limit(7) + + expect(stream.raw).to eq('') + end + + it 'forwards to the next linefeed, case 2' do + stream.limit(29) + + expect(stream.raw).to eq("\e[01;32m許功蓋\e[0m\n") + end end end diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index 6d6c9f2adfc..eff41d85972 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -34,8 +34,18 @@ describe ContainerRepository do end describe '#path' do - it 'returns a full path to the repository' do - expect(repository.path).to eq('group/test/my_image') + context 'when project path does not contain uppercase letters' do + it 'returns a full path to the repository' do + expect(repository.path).to eq('group/test/my_image') + end + end + + context 'when path contains uppercase letters' do + let(:project) { create(:project, path: 'MY_PROJECT', group: group) } + + it 'returns a full path without capital letters' do + expect(repository.path).to eq('group/my_project/my_image') + end end end diff --git a/spec/support/fixture_helpers.rb b/spec/support/fixture_helpers.rb index a05c9d18002..5515c355cea 100644 --- a/spec/support/fixture_helpers.rb +++ b/spec/support/fixture_helpers.rb @@ -1,8 +1,11 @@ module FixtureHelpers def fixture_file(filename) return '' if filename.blank? - file_path = File.expand_path(Rails.root.join('spec/fixtures/', filename)) - File.read(file_path) + File.read(expand_fixture_path(filename)) + end + + def expand_fixture_path(filename) + File.expand_path(Rails.root.join('spec/fixtures/', filename)) end end diff --git a/vendor/assets/javascripts/notebooklab.js b/vendor/assets/javascripts/notebooklab.js index 601a645b655..b8cfdc53b48 100644 --- a/vendor/assets/javascripts/notebooklab.js +++ b/vendor/assets/javascripts/notebooklab.js @@ -699,6 +699,48 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de // // +var renderer = new _marked2.default.Renderer(); + +/* + Regex to match KaTex blocks. + + Supports the following: + + \begin{equation}<math>\end{equation} + $$<math>$$ + inline $<math>$ + + The matched text then goes through the KaTex renderer & then outputs the HTML +*/ +var katexRegexString = '(\n ^\\\\begin{[a-zA-Z]+}\\s\n |\n ^\\$\\$\n |\n \\s\\$(?!\\$)\n)\n (.+?)\n(\n \\s\\\\end{[a-zA-Z]+}$\n |\n \\$\\$$\n |\n \\$\n)\n'.replace(/\s/g, '').trim(); + +renderer.paragraph = function (t) { + var text = t; + var inline = false; + + if (typeof katex !== 'undefined') { + var katexString = text.replace(/\\/g, '\\'); + var matches = new RegExp(katexRegexString, 'gi').exec(katexString); + + if (matches && matches.length > 0) { + if (matches[1].trim() === '$' && matches[3].trim() === '$') { + inline = true; + + text = katexString.replace(matches[0], '') + ' ' + katex.renderToString(matches[2]); + } else { + text = katex.renderToString(matches[2]); + } + } + } + + return '<p class="' + (inline ? 'inline-katex' : '') + '">' + text + '</p>'; +}; + +_marked2.default.setOptions({ + sanitize: true, + renderer: renderer +}); + exports.default = { components: { prompt: _prompt2.default @@ -711,20 +753,7 @@ exports.default = { }, computed: { markdown: function markdown() { - var regex = new RegExp('^\\$\\$(.*)\\$\\$$', 'g'); - - var source = this.cell.source.map(function (line) { - var matches = regex.exec(line.trim()); - - // Only render use the Katex library if it is actually loaded - if (matches && matches.length > 0 && typeof katex !== 'undefined') { - return katex.renderToString(matches[1]); - } - - return line; - }); - - return (0, _marked2.default)(source.join('')); + return (0, _marked2.default)(this.cell.source.join('')); } } }; @@ -3047,7 +3076,7 @@ exports = module.exports = __webpack_require__(1)(undefined); // module -exports.push([module.i, ".markdown .katex{display:block;text-align:center}", ""]); +exports.push([module.i, ".markdown .katex{display:block;text-align:center}.markdown .inline-katex .katex{display:inline;text-align:initial}", ""]); // exports |