summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-24 06:07:07 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-24 06:07:07 +0000
commit12287a65b735d784cda3555d1b261e50b461b29e (patch)
treee7539b1b3672986a4f41b544f913ee120d623d44
parent24ed154fa81265f47bcfbecfcb331f82a5faad0d (diff)
downloadgitlab-ce-12287a65b735d784cda3555d1b261e50b461b29e.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/blob/blob_utils.js5
-rw-r--r--app/assets/javascripts/blob/viewer/index.js58
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js20
-rw-r--r--app/assets/stylesheets/framework/files.scss11
-rw-r--r--app/assets/stylesheets/highlight/common.scss9
-rw-r--r--app/assets/stylesheets/highlight/themes/dark.scss5
-rw-r--r--app/assets/stylesheets/highlight/themes/monokai.scss5
-rw-r--r--app/assets/stylesheets/highlight/themes/none.scss6
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-dark.scss5
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-light.scss5
-rw-r--r--app/assets/stylesheets/highlight/white_base.scss5
-rw-r--r--app/views/shared/_file_highlight.html.haml2
-rw-r--r--changelogs/unreleased/mfluharty-clickable-links-in-file-view.yml5
-rw-r--r--doc/administration/geo/replication/configuration.md12
-rw-r--r--doc/administration/geo/replication/troubleshooting.md30
-rw-r--r--doc/ci/multi_project_pipelines.md7
-rw-r--r--doc/development/profiling.md4
-rw-r--r--qa/qa/page/project/issue/show.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb13
-rw-r--r--spec/features/projects/blobs/edit_spec.rb7
-rw-r--r--spec/javascripts/blob/viewer/index_spec.js49
21 files changed, 177 insertions, 90 deletions
diff --git a/app/assets/javascripts/blob/blob_utils.js b/app/assets/javascripts/blob/blob_utils.js
new file mode 100644
index 00000000000..27fcc7f7b79
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_utils.js
@@ -0,0 +1,5 @@
+// capture anything starting with http:// or https://
+// up until a disallowed character or whitespace
+export const blobLinkRegex = /https?:\/\/[^"<>\\^`{|}\s]+/g;
+
+export default { blobLinkRegex };
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index 07e4dde41d9..f032c2f216b 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -4,6 +4,10 @@ import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils';
import { __ } from '~/locale';
+import { blobLinkRegex } from '~/blob/blob_utils';
+
+const SIMPLE_VIEWER_NAME = 'simple';
+const RICH_VIEWER_NAME = 'rich';
export default class BlobViewer {
constructor() {
@@ -21,7 +25,7 @@ export default class BlobViewer {
}
static initRichViewer() {
- const viewer = document.querySelector('.blob-viewer[data-type="rich"]');
+ const viewer = document.querySelector(`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`);
if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise =>
@@ -61,8 +65,12 @@ export default class BlobViewer {
this.switcherBtns = document.querySelectorAll('.js-blob-viewer-switch-btn');
this.copySourceBtn = document.querySelector('.js-copy-blob-source-btn');
- this.simpleViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="simple"]');
- this.richViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="rich"]');
+ this.simpleViewer = this.$fileHolder[0].querySelector(
+ `.blob-viewer[data-type="${SIMPLE_VIEWER_NAME}"]`,
+ );
+ this.richViewer = this.$fileHolder[0].querySelector(
+ `.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`,
+ );
this.initBindings();
@@ -71,10 +79,10 @@ export default class BlobViewer {
switchToInitialViewer() {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
- let initialViewerName = initialViewer.getAttribute('data-type');
+ let initialViewerName = initialViewer.dataset.type;
if (this.switcher && window.location.hash.indexOf('#L') === 0) {
- initialViewerName = 'simple';
+ initialViewerName = SIMPLE_VIEWER_NAME;
}
this.switchToViewer(initialViewerName);
@@ -91,35 +99,41 @@ export default class BlobViewer {
this.copySourceBtn.addEventListener('click', () => {
if (this.copySourceBtn.classList.contains('disabled')) return this.copySourceBtn.blur();
- return this.switchToViewer('simple');
+ return this.switchToViewer(SIMPLE_VIEWER_NAME);
});
}
}
+ static linkifyURLs(viewer) {
+ if (viewer.dataset.linkified) return;
+
+ document.querySelectorAll('.js-blob-content .code .line').forEach(line => {
+ // eslint-disable-next-line no-param-reassign
+ line.innerHTML = line.innerHTML.replace(blobLinkRegex, '<a href="$&">$&</a>');
+ });
+
+ // eslint-disable-next-line no-param-reassign
+ viewer.dataset.linkified = true;
+ }
+
switchViewHandler(e) {
const target = e.currentTarget;
e.preventDefault();
- this.switchToViewer(target.getAttribute('data-viewer'));
+ this.switchToViewer(target.dataset.viewer);
}
toggleCopyButtonState() {
if (!this.copySourceBtn) return;
- if (this.simpleViewer.getAttribute('data-loaded')) {
- this.copySourceBtn.setAttribute('title', __('Copy file contents'));
+ if (this.simpleViewer.dataset.loaded) {
+ this.copySourceBtn.dataset.title = __('Copy file contents');
this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) {
- this.copySourceBtn.setAttribute(
- 'title',
- __('Wait for the file to load to copy its contents'),
- );
+ this.copySourceBtn.dataset.title = __('Wait for the file to load to copy its contents');
this.copySourceBtn.classList.add('disabled');
} else {
- this.copySourceBtn.setAttribute(
- 'title',
- __('Switch to the source to copy the file contents'),
- );
+ this.copySourceBtn.dataset.title = __('Switch to the source to copy the file contents');
this.copySourceBtn.classList.add('disabled');
}
@@ -159,6 +173,8 @@ export default class BlobViewer {
this.$fileHolder.trigger('highlight:line');
handleLocationHash();
+ if (name === SIMPLE_VIEWER_NAME) BlobViewer.linkifyURLs(viewer);
+
this.toggleCopyButtonState();
})
.catch(() => new Flash(__('Error loading viewer')));
@@ -166,17 +182,17 @@ export default class BlobViewer {
static loadViewer(viewerParam) {
const viewer = viewerParam;
- const url = viewer.getAttribute('data-url');
+ const { url, loaded, loading } = viewer.dataset;
- if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
+ if (!url || loaded || loading) {
return Promise.resolve(viewer);
}
- viewer.setAttribute('data-loading', 'true');
+ viewer.dataset.loading = true;
return axios.get(url).then(({ data }) => {
viewer.innerHTML = data.html;
- viewer.setAttribute('data-loaded', 'true');
+ viewer.dataset.loaded = true;
return viewer;
});
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 011898a5e7a..8561f650e8f 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -4,7 +4,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
-import TemplateSelectorMediator from '../blob/file_template_mediator';
+import { blobLinkRegex } from '~/blob/blob_utils';
+import TemplateSelectorMediator from '~/blob/file_template_mediator';
import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
@@ -17,6 +18,7 @@ export default class EditBlob {
this.initModePanesAndLinks();
this.initSoftWrap();
this.initFileSelectors();
+ this.initBlobContentLinkClickability();
}
configureAceEditor() {
@@ -89,6 +91,22 @@ export default class EditBlob {
return this.editor.focus();
}
+ initBlobContentLinkClickability() {
+ this.editor.renderer.on('afterRender', () => {
+ document.querySelectorAll('.ace_text-layer .ace_line > *').forEach(token => {
+ if (token.dataset.linkified || !token.textContent.includes('http')) return;
+
+ // eslint-disable-next-line no-param-reassign
+ token.innerHTML = token.innerHTML.replace(
+ blobLinkRegex,
+ '<a target="_blank" href="$&">$&</a>',
+ );
+ // eslint-disable-next-line no-param-reassign
+ token.dataset.linkified = true;
+ });
+ });
+ }
+
initSoftWrap() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 487fbf0fcff..96dac7ba836 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -258,6 +258,17 @@
}
}
}
+
+ .file-editor {
+ .ace_underline {
+ text-decoration: none;
+ }
+
+ .ace_line a {
+ pointer-events: auto;
+ color: inherit;
+ }
+ }
}
span.idiff {
diff --git a/app/assets/stylesheets/highlight/common.scss b/app/assets/stylesheets/highlight/common.scss
index bdeac7e97c0..95f6fb8c333 100644
--- a/app/assets/stylesheets/highlight/common.scss
+++ b/app/assets/stylesheets/highlight/common.scss
@@ -29,3 +29,12 @@
color: $link;
}
}
+
+// Links to URLs, emails, or dependencies
+.code .line a {
+ color: inherit;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss
index cbce0ba3f1e..16e6824baf8 100644
--- a/app/assets/stylesheets/highlight/themes/dark.scss
+++ b/app/assets/stylesheets/highlight/themes/dark.scss
@@ -193,11 +193,6 @@ $dark-il: #de935f;
color: $dark-highlight-color !important;
}
- // Links to URLs, emails, or dependencies
- .line a {
- color: $dark-na;
- }
-
.hll { background-color: $dark-hll-bg; }
.c { color: $dark-c; } /* Comment */
.err { color: $dark-err; } /* Error */
diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss
index 1b61ffa37e3..cfbb7a1db94 100644
--- a/app/assets/stylesheets/highlight/themes/monokai.scss
+++ b/app/assets/stylesheets/highlight/themes/monokai.scss
@@ -193,11 +193,6 @@ $monokai-gi: #a6e22e;
color: $black !important;
}
- // Links to URLs, emails, or dependencies
- .line a {
- color: $monokai-k;
- }
-
.hll { background-color: $monokai-hll; }
.c { color: $monokai-c; } /* Comment */
.err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */
diff --git a/app/assets/stylesheets/highlight/themes/none.scss b/app/assets/stylesheets/highlight/themes/none.scss
index a7ede266fb5..a099563542d 100644
--- a/app/assets/stylesheets/highlight/themes/none.scss
+++ b/app/assets/stylesheets/highlight/themes/none.scss
@@ -143,12 +143,6 @@
background-color: $white-normal;
}
- // Links to URLs, emails, or dependencies
- .line a {
- color: $gl-text-color;
- text-decoration: underline;
- }
-
.hll { background-color: $white-light; }
.gd {
diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
index 6569f3abc8b..d74d5c6ebda 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
@@ -196,11 +196,6 @@ $solarized-dark-il: #2aa198;
background-color: $solarized-dark-highlight !important;
}
- // Links to URLs, emails, or dependencies
- .line a {
- color: $solarized-dark-kd;
- }
-
/* Solarized Dark
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss
index 4e74a9ea50a..d995c5bba1f 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-light.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss
@@ -204,11 +204,6 @@ $solarized-light-il: #2aa198;
background-color: $solarized-light-highlight !important;
}
- // Links to URLs, emails, or dependencies
- .line a {
- color: $solarized-light-kd;
- }
-
/* Solarized Light
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss
index 973f94c63aa..c58cf89f0ca 100644
--- a/app/assets/stylesheets/highlight/white_base.scss
+++ b/app/assets/stylesheets/highlight/white_base.scss
@@ -209,11 +209,6 @@ span.highlight_word {
background-color: $white-highlight !important;
}
-// Links to URLs, emails, or dependencies
-.line a {
- color: $white-nb;
-}
-
.hll { background-color: $white-hll-bg; }
.c { color: $white-c;
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index d7e57fc0d01..4e609f50993 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -10,7 +10,7 @@
%a.diff-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i }
= link_icon
= i
- .blob-content{ data: { blob_id: blob.id } }
+ .blob-content.js-blob-content{ data: { blob_id: blob.id } }
%pre.code.highlight
%code
= blob.present.highlight
diff --git a/changelogs/unreleased/mfluharty-clickable-links-in-file-view.yml b/changelogs/unreleased/mfluharty-clickable-links-in-file-view.yml
new file mode 100644
index 00000000000..e6d42e10c19
--- /dev/null
+++ b/changelogs/unreleased/mfluharty-clickable-links-in-file-view.yml
@@ -0,0 +1,5 @@
+---
+title: Make URLs in blob viewer and blob editor into clickable links
+merge_request: 18305
+author:
+type: added
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index f09d9f20dab..44baab40153 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -187,14 +187,18 @@ keys must be manually replicated to the **secondary** node.
1. Visit the **primary** node's **Admin Area > Geo**
(`/admin/geo/nodes`) in your browser.
1. Click the **New node** button.
-1. Add the **secondary** node. Use the **exact** name you inputed for `gitlab_rails['geo_node_name']` as the Name and the full URL as the URL. **Do NOT** check the
- **This is a primary node** checkbox.
-
![Add secondary node](img/adding_a_secondary_node.png)
+1. Fill in **Name** with the `gitlab_rails['geo_node_name']` in
+ `/etc/gitlab/gitlab.rb`. These values must always match *exactly*, character
+ for character.
+1. Fill in **URL** with the `external_url` in `/etc/gitlab/gitlab.rb`. These
+ values must always match, but it doesn't matter if one ends with a `/` and
+ the other doesn't.
+1. **Do NOT** check the **This is a primary node** checkbox.
1. Optionally, choose which groups or storage shards should be replicated by the
**secondary** node. Leave blank to replicate all. Read more in
[selective synchronization](#selective-synchronization).
-1. Click the **Add node** button.
+1. Click the **Add node** button to add the **secondary** node.
1. SSH into your GitLab **secondary** server and restart the services:
```sh
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 4d64941411a..0c74e2d6ac7 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -115,11 +115,19 @@ Any **secondary** nodes should point only to read-only instances.
#### Can Geo detect the current node correctly?
-Geo uses the defined node from the **Admin Area > Geo** screen, and tries to match
-it with the value defined in the `/etc/gitlab/gitlab.rb` configuration file.
-The relevant line looks like: `external_url "http://gitlab.example.com"`.
+Geo finds the current machine's name in `/etc/gitlab/gitlab.rb` by first looking
+for `gitlab_rails['geo_node_name']`. If it is not defined, then it defaults to
+the external URL defined in e.g. `external_url "http://gitlab.example.com"`. To
+get a machine's name, run:
-To check if the node on the current machine is correctly detected type:
+```sh
+sudo gitlab-rails runner "puts GeoNode.current_node_name"
+```
+
+This name is used to look up the node with the same **Name** in
+**Admin Area > Geo**.
+
+To check if current machine is correctly finding its node:
```sh
sudo gitlab-rails runner "puts Gitlab::Geo.current_node.inspect"
@@ -511,6 +519,20 @@ to [cleanup orphan artifact files](../../../raketasks/cleanup.md#remove-orphan-a
On a Geo **secondary** node, this command will also clean up all Geo
registry record related to the orphan files on disk.
+## Fixing sign in errors
+
+### Message: The redirect URI included is not valid
+
+If you are able to log in to the **primary** node, but you receive this error
+when attempting to log into a **secondary**, you should check that the Geo
+node's URL matches its external URL.
+
+1. On the primary, visit **Admin Area > Geo**.
+1. Find the affected **secondary** and click **Edit**.
+1. Ensure the **URL** field matches the value found in `/etc/gitlab/gitlab.rb`
+ in `external_url "https://gitlab.example.com"` on the frontend server(s) of
+ the **secondary** node.
+
## Fixing common errors
This section documents common errors reported in the Admin UI and how to fix them.
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 093d334e937..f13d05716f1 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -87,10 +87,9 @@ not be found, or a user does not have access rights to create pipeline there,
the `staging` job is going to be marked as _failed_.
CAUTION: **Caution:**
-`staging` will succeed as soon as a downstream pipeline gets created.
-GitLab does not support status attribution yet, however adding first-class
-`trigger` configuration syntax is ground work for implementing
-[status attribution](https://gitlab.com/gitlab-org/gitlab-foss/issues/39640).
+In the example, `staging` will be marked as succeeded as soon as a downstream pipeline
+gets created. If you want to display the downstream pipeline's status instead, see
+[Mirroring status from triggered pipeline](#mirroring-status-from-triggered-pipeline).
NOTE: **Note:**
Bridge jobs do not support every configuration entry that a user can use
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
index 04897e770f8..18683fa10f8 100644
--- a/doc/development/profiling.md
+++ b/doc/development/profiling.md
@@ -42,6 +42,10 @@ Passing a `logger:` keyword argument to `Gitlab::Profiler.profile` will send
ActiveRecord and ActionController log output to that logger. Further options are
documented with the method source.
+```ruby
+Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first, logger: Logger.new(STDOUT))
+```
+
There is also a RubyProf printer available:
`Gitlab::Profiler::TotalTimeFlatPrinter`. This acts like
`RubyProf::FlatPrinter`, but its `min_percent` option works on the method's
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 8f5632f7e6e..6ec80b7c9cc 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -108,6 +108,10 @@ module QA
find_element(:more_assignees_link)
end
+ def noteable_note_item
+ find_element(:noteable_note_item)
+ end
+
def select_all_activities_filter
select_filter_with_text('Show all activity')
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index 04ae4963d3a..300bf59eba4 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -21,8 +21,9 @@ module QA
end
context 'when using attachments in comments', :object_storage do
+ let(:gif_file_name) { 'banana_sample.gif' }
let(:file_to_attach) do
- File.absolute_path(File.join('spec', 'fixtures', 'banana_sample.gif'))
+ File.absolute_path(File.join('spec', 'fixtures', gif_file_name))
end
before do
@@ -37,15 +38,7 @@ module QA
Page::Project::Issue::Show.perform do |show|
show.comment('See attached banana for scale', attachment: file_to_attach)
- show.refresh
-
- image_url = find('a[href$="banana_sample.gif"]')[:href]
-
- found = show.wait(reload: false) do
- show.asset_exists?(image_url)
- end
-
- expect(found).to be_truthy
+ expect(show.noteable_note_item.find("img[src$='#{gif_file_name}']")).to be_visible
end
end
end
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index 3b32d213754..e02a4579095 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -60,6 +60,13 @@ describe 'Editing file blob', :js do
expect(page).to have_content 'NextFeature'
end
+ it 'renders a URL in the content of file as a link' do
+ project.repository.create_file(user, 'file.yml', '# go to https://gitlab.com', message: 'testing', branch_name: branch)
+ visit project_edit_blob_path(project, tree_join(branch, 'file.yml'))
+
+ expect(page).to have_selector('.ace_content .ace_line a')
+ end
+
context 'from blob file path' do
before do
visit project_blob_path(project, tree_join(branch, file_path))
diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js
index 06c06613887..bbc59632f3c 100644
--- a/spec/javascripts/blob/viewer/index_spec.js
+++ b/spec/javascripts/blob/viewer/index_spec.js
@@ -11,6 +11,13 @@ describe('Blob viewer', () => {
preloadFixtures('snippets/show.html');
+ const asyncClick = () =>
+ new Promise(resolve => {
+ document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
+
+ setTimeout(resolve);
+ });
+
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -66,19 +73,12 @@ describe('Blob viewer', () => {
});
it('doesnt reload file if already loaded', done => {
- const asyncClick = () =>
- new Promise(resolve => {
- document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
-
- setTimeout(resolve);
- });
-
asyncClick()
.then(() => asyncClick())
.then(() => {
- expect(
- document.querySelector('.blob-viewer[data-type="simple"]').getAttribute('data-loaded'),
- ).toBe('true');
+ expect(document.querySelector('.blob-viewer[data-type="simple"]').dataset.loaded).toBe(
+ 'true',
+ );
done();
})
@@ -100,9 +100,7 @@ describe('Blob viewer', () => {
});
it('has tooltip when disabled', () => {
- expect(copyButton.getAttribute('data-original-title')).toBe(
- 'Switch to the source to copy the file contents',
- );
+ expect(copyButton.dataset.title).toBe('Switch to the source to copy the file contents');
});
it('is blurred when clicked and disabled', () => {
@@ -136,7 +134,7 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
- expect(copyButton.getAttribute('data-original-title')).toBe('Copy file contents');
+ expect(copyButton.dataset.title).toBe('Copy file contents');
done();
});
@@ -177,4 +175,27 @@ describe('Blob viewer', () => {
expect(axios.get.calls.count()).toBe(1);
});
});
+
+ describe('a URL inside the blob content', () => {
+ beforeEach(() => {
+ mock.onGet('http://test.host/snippets/1.json?viewer=simple').reply(200, {
+ html:
+ '<div class="js-blob-content"><pre class="code"><code><span class="line" lang="yaml"><span class="c1">To install gitlab-shell you also need a Go compiler version 1.8 or newer. https://golang.org/dl/</span></span></code></pre></div>',
+ });
+ });
+
+ it('is rendered as a link in simple view', done => {
+ asyncClick()
+ .then(() => {
+ expect(document.querySelector('.blob-viewer[data-type="simple"]').innerHTML).toContain(
+ '<a href="https://golang.org/dl/">https://golang.org/dl/</a>',
+ );
+ done();
+ })
+ .catch(() => {
+ fail();
+ done();
+ });
+ });
+ });
});