Commit a6c61599 authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett

Merge branch 'master' into update-droplab-to-webpack-version

parents fefd5a08 fec40d78
...@@ -476,10 +476,10 @@ AwardsHandler.prototype.setupSearch = function setupSearch() { ...@@ -476,10 +476,10 @@ AwardsHandler.prototype.setupSearch = function setupSearch() {
this.registerEventListener('on', $('input.emoji-search'), 'input', (e) => { this.registerEventListener('on', $('input.emoji-search'), 'input', (e) => {
const term = $(e.target).val().trim(); const term = $(e.target).val().trim();
// Clean previous search results // Clean previous search results
$('ul.emoji-menu-search, h5.emoji-search').remove(); $('ul.emoji-menu-search, h5.emoji-search-title').remove();
if (term.length > 0) { if (term.length > 0) {
// Generate a search result block // Generate a search result block
const h5 = $('<h5 class="emoji-search" />').text('Search results'); const h5 = $('<h5 class="emoji-search-title"/>').text('Search results');
const foundEmojis = this.searchEmojis(term).show(); const foundEmojis = this.searchEmojis(term).show();
const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis); const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis);
$('.emoji-menu-content ul, .emoji-menu-content h5').hide(); $('.emoji-menu-content ul, .emoji-menu-content h5').hide();
......
/* eslint-disable no-new */
import Vue from 'vue';
import PDFLab from 'vendor/pdflab';
import workerSrc from 'vendor/pdf.worker';
Vue.use(PDFLab, {
workerSrc,
});
export default () => {
const el = document.getElementById('js-pdf-viewer');
new Vue({
el,
data() {
return {
error: false,
loadError: false,
loading: true,
pdf: el.dataset.endpoint,
};
},
methods: {
onLoad() {
this.loading = false;
},
onError(error) {
this.loading = false;
this.loadError = true;
this.error = error;
},
},
template: `
<div class="container-fluid md prepend-top-default append-bottom-default">
<div
class="text-center loading"
v-if="loading && !error">
<i
class="fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="PDF loading">
</i>
</div>
<pdf-lab
v-if="!loadError"
:pdf="pdf"
@pdflabload="onLoad"
@pdflaberror="onError" />
<p
class="text-center"
v-if="error">
<span v-if="loadError">
An error occured whilst loading the file. Please try again later.
</span>
<span v-else>
An error occured whilst decoding the file.
</span>
</p>
</div>
`,
});
};
import renderPDF from './pdf';
document.addEventListener('DOMContentLoaded', renderPDF);
import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
export default class SketchLoader {
constructor(container) {
this.container = container;
this.loadingIcon = this.container.querySelector('.js-loading-icon');
this.load();
}
load() {
return this.getZipFile()
.then(data => JSZip.loadAsync(data))
.then(asyncResult => asyncResult.files['previews/preview.png'].async('uint8array'))
.then((content) => {
const url = window.URL || window.webkitURL;
const blob = new Blob([new Uint8Array(content)], {
type: 'image/png',
});
const previewUrl = url.createObjectURL(blob);
this.render(previewUrl);
})
.catch(this.error.bind(this));
}
getZipFile() {
return new JSZip.external.Promise((resolve, reject) => {
JSZipUtils.getBinaryContent(this.container.dataset.endpoint, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
render(previewUrl) {
const previewLink = document.createElement('a');
const previewImage = document.createElement('img');
previewLink.href = previewUrl;
previewLink.target = '_blank';
previewImage.src = previewUrl;
previewImage.className = 'img-responsive';
previewLink.appendChild(previewImage);
this.container.appendChild(previewLink);
this.removeLoadingIcon();
}
error() {
const errorMsg = document.createElement('p');
errorMsg.className = 'prepend-top-default append-bottom-default text-center';
errorMsg.textContent = `
Cannot show preview. For previews on sketch files, they must have the file format
introduced by Sketch version 43 and above.
`;
this.container.appendChild(errorMsg);
this.removeLoadingIcon();
}
removeLoadingIcon() {
if (this.loadingIcon) {
this.loadingIcon.remove();
}
}
}
/* eslint-disable no-new */
import SketchLoader from './sketch';
document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('js-sketch-viewer');
new SketchLoader(el);
});
...@@ -45,14 +45,14 @@ window.GroupsSelect = (function() { ...@@ -45,14 +45,14 @@ window.GroupsSelect = (function() {
page, page,
per_page: GroupsSelect.PER_PAGE, per_page: GroupsSelect.PER_PAGE,
all_available, all_available,
skip_groups,
}; };
}, },
results: function (data, page) { results: function (data, page) {
if (data.length) return { results: [] }; if (data.length) return { results: [] };
const results = data.length ? data : data.results || []; const groups = data.length ? data : data.results || [];
const more = data.pagination ? data.pagination.more : false; const more = data.pagination ? data.pagination.more : false;
const results = groups.filter(group => skip_groups.indexOf(group.id) === -1);
return { return {
results, results,
......
...@@ -292,6 +292,10 @@ ...@@ -292,6 +292,10 @@
} }
@media(min-width: $screen-xs-max) { @media(min-width: $screen-xs-max) {
&.merge-requests .text-content {
margin-top: 40px;
}
&.labels .text-content { &.labels .text-content {
margin-top: 70px; margin-top: 70px;
} }
......
...@@ -10,6 +10,7 @@ class Groups::ApplicationController < ApplicationController ...@@ -10,6 +10,7 @@ class Groups::ApplicationController < ApplicationController
unless @group unless @group
id = params[:group_id] || params[:id] id = params[:group_id] || params[:id]
@group = Group.find_by_full_path(id) @group = Group.find_by_full_path(id)
@group_merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id).execute
unless @group && can?(current_user, :read_group, @group) unless @group && can?(current_user, :read_group, @group)
@group = nil @group = nil
......
...@@ -46,10 +46,18 @@ class Blob < SimpleDelegator ...@@ -46,10 +46,18 @@ class Blob < SimpleDelegator
text? && language && language.name == 'SVG' text? && language && language.name == 'SVG'
end end
def pdf?
name && File.extname(name) == '.pdf'
end
def ipython_notebook? def ipython_notebook?
text? && language&.name == 'Jupyter Notebook' text? && language&.name == 'Jupyter Notebook'
end end
def sketch?
binary? && extname.downcase.delete('.') == 'sketch'
end
def size_within_svg_limits? def size_within_svg_limits?
size <= MAXIMUM_SVG_SIZE size <= MAXIMUM_SVG_SIZE
end end
...@@ -67,8 +75,12 @@ class Blob < SimpleDelegator ...@@ -67,8 +75,12 @@ class Blob < SimpleDelegator
end end
elsif image? || svg? elsif image? || svg?
'image' 'image'
elsif pdf?
'pdf'
elsif ipython_notebook? elsif ipython_notebook?
'notebook' 'notebook'
elsif sketch?
'sketch'
elsif text? elsif text?
'text' 'text'
else else
......
- page_title "Merge Requests" - page_title "Merge Requests"
.top-area - if @group_merge_requests.empty?
= render 'shared/issuable/nav', type: :merge_requests = render 'shared/empty_states/merge_requests', project_select_button: true
- if current_user - else
.nav-controls .top-area
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New Merge Request" = render 'shared/issuable/nav', type: :merge_requests
- if current_user
.nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request"
= render 'shared/issuable/filter', type: :merge_requests = render 'shared/issuable/filter', type: :merge_requests
.row-content-block.second-block .row-content-block.second-block
Only merge requests from Only merge requests from
%strong= @group.name %strong= @group.name
group are listed here. group are listed here.
- if current_user - if current_user
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
= render 'shared/merge_requests' .prepend-top-default
= render 'shared/merge_requests'
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('pdf_viewer')
.file-content#js-pdf-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } }
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('sketch_viewer')
.file-content#js-sketch-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } }
.js-loading-icon.text-center.prepend-top-default.append-bottom-default.js-loading-icon{ 'aria-label' => 'Loading Sketch preview' }
= icon('spinner spin 2x', 'aria-hidden' => 'true');
%ul.content-list.mr-list.issuable-list %ul.content-list.mr-list.issuable-list
= render @merge_requests - if @merge_requests.exists?
- if @merge_requests.blank? = render @merge_requests
%li - else
.nothing-here-block No merge requests to show = render 'shared/empty_states/merge_requests'
- if @merge_requests.present? - if @merge_requests.present?
= paginate @merge_requests, theme: "gitlab" = paginate @merge_requests, theme: "gitlab"
...@@ -7,16 +7,19 @@ ...@@ -7,16 +7,19 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('filtered_search') = page_specific_javascript_bundle_tag('filtered_search')
%div{ class: container_class } - if @project.merge_requests.exists?
.top-area %div{ class: container_class }
= render 'shared/issuable/nav', type: :merge_requests .top-area
.nav-controls = render 'shared/issuable/nav', type: :merge_requests
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) .nav-controls
- if merge_project - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do - if merge_project
New Merge Request = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New merge request" do
New merge request
= render 'shared/issuable/search_bar', type: :merge_requests = render 'shared/issuable/search_bar', type: :merge_requests
.merge-requests-holder .merge-requests-holder
= render 'merge_requests' = render 'merge_requests'
- else
= render 'shared/empty_states/merge_requests', button_path: new_namespace_project_merge_request_path(@project.namespace, @project)
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
= paginate @merge_requests, theme: "gitlab" = paginate @merge_requests, theme: "gitlab"
- else - else
.nothing-here-block No merge requests to show = render 'shared/empty_states/merge_requests'
- button_path = local_assigns.fetch(:button_path, false)
- project_select_button = local_assigns.fetch(:project_select_button, false)
- has_button = button_path || project_select_button
.row.empty-state.merge-requests
.col-xs-12{ class: "#{'col-sm-6 pull-right' if has_button}" }
.svg-content
= render 'shared/empty_states/icons/merge_requests.svg'
.col-xs-12{ class: "#{'col-sm-6' if has_button}" }
.text-content
- if has_button
%h4
Merge requests are a place to propose changes you've made to a project and discuss those changes with others.
%p
Interested parties can even contribute by pushing commits if they want to.
- if project_select_button
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: 'New merge request'
- else
= link_to 'New merge request', button_path, class: 'btn btn-new', title: 'New merge request', id: 'new_merge_request_link'
- else
%h4.text-center
There are no merge requests to show.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="755 221 385 225" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="278" height="179" rx="10"/><mask id="d" width="278" height="179" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><path id="b" d="M13.6 49H57c5.5 0 10-4.5 10-10V10c0-5.5-4.5-10-10-10H10C4.5 0 0 4.5 0 10v42c0 5.5 3.2 7 7.2 3l6.4-6z"/><mask id="e" width="67" height="57.2" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><path id="c" d="M13.6 49H57c5.5 0 10-4.5 10-10V10c0-5.5-4.5-10-10-10H10C4.5 0 0 4.5 0 10v42c0 5.5 3.2 7 7.2 3l6.4-6z"/><mask id="f" width="67" height="57.2" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd"><g fill="#F9F9F9" transform="translate(752 227)"><rect width="120" height="22" x="30" rx="11"/><rect width="132" height="22" y="44" rx="11"/><rect width="190" height="22" x="208" y="66" rx="11"/><rect width="158" height="22" x="129" y="197" rx="11"/><rect width="158" height="22" x="66" y="154" rx="11"/><rect width="350" height="22" x="31" y="110" rx="11"/><path d="M153 22H21h21.5c6 0 11 5 11 11s-5 11-11 11H21h132-36.5c-6 0-11-5-11-11s5-11 11-11H153zm252 66H288h36.5c6 0 11 5 11 11s-5 11-11 11H288h117-36.5c-6 0-11-5-11-11s5-11 11-11H405zm-244 44H44h36.5c6 0 11 5 11 11s-5 11-11 11H44h117-36.5c-6 0-11-5-11-11s5-11 11-11H161zm75 44H119h21.5c6 0 11 5 11 11s-5 11-11 11H119h117-51.5c-6 0-11-5-11-11s5-11 11-11H236z"/></g><g transform="translate(812 240)"><use fill="#FFF" stroke="#EEE" stroke-width="8" mask="url(#d)" xlink:href="#a"/><path fill="#EEE" d="M4 29h271v4H4z"/><g transform="translate(34 60)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(34 93)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#FC6D26" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#FC6D26" opacity=".5" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#EEE" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" opacity=".5" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(34 126)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#EEE" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" opacity=".5" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(157 59)"><rect width="6" height="2" y="1" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="48" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#6B4FBB" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="23" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="34" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" y="33" fill="#EEE" rx="2"/><rect width="15" height="4" x="58" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="55" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="15" height="4" x="29" y="44" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="48" y="33" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="15" y="55" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" y="33" fill="#EEE" rx="2"/><rect width="10" height="4" x="15" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="48" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="62" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="77" y="22" fill="#EEE" rx="2"/><rect width="6" height="2" y="45" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="56" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="67" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" y="66" fill="#6B4FBB" rx="2"/><rect width="15" height="4" x="39" y="88" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="77" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="88" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="77" fill="#6B4FBB" rx="2"/><rect width="10" height="4" x="34" y="66" fill="#EEE" rx="2"/><rect width="10" height="4" x="72" y="77" fill="#EEE" rx="2"/><rect width="10" height="4" x="15" y="77" fill="#EEE" rx="2"/><rect width="6" height="2" y="78" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="89" fill="#FDE5D8" rx="1"/></g></g><g transform="translate(1057 221)"><use fill="#FFF" stroke="#FDE5D8" stroke-width="8" mask="url(#e)" xlink:href="#b"/><rect width="29" height="3" x="14" y="14" fill="#FDB692" rx="1.5"/><rect width="39" height="3" x="14" y="23" fill="#FDB692" rx="1.5"/><rect width="29" height="3" x="14" y="32" fill="#FDB692" rx="1.5"/></g><g transform="translate(1046 285)"><circle cx="16" cy="15" r="15" fill="#FFF7F4" stroke="#FC6D26" stroke-width="3"/><path stroke="#FC6D26" stroke-width="2" d="M0 14h1c5 0 9.2-2.7 11.4-6.7M14 1V0"/><path stroke="#FC6D26" stroke-width="2" d="M7.8 3c3 4.3 7.8 7 13.2 7 3.3 0 6.3-1 9-2.7"/><circle cx="10.5" cy="17.5" r="1.5" fill="#FC6D26"/><circle cx="21.5" cy="17.5" r="1.5" fill="#FC6D26"/></g><g transform="translate(825 370)"><circle cx="15" cy="16" r="15" fill="#F4F1FA" stroke="#6B4FBB" stroke-width="3"/><path fill="#6B4FBB" d="M25 7h2.7C25 2.8 20.4 0 15 0 9.6 0 5 2.8 2.3 7H5l2.5-3L10 7l2.5-3L15 7l2.5-3L20 7l2.5-3L25 7z"/><circle cx="9.5" cy="17.5" r="1.5" fill="#6B4FBB"/><circle cx="20.5" cy="17.5" r="1.5" fill="#6B4FBB"/></g><g transform="matrix(-1 0 0 1 840 306)"><use fill="#FFF" stroke="#E2DCF2" stroke-width="8" mask="url(#f)" xlink:href="#c"/><rect width="29" height="3" x="24" y="14" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="19" height="3" x="34" y="23" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="19" height="3" x="34" y="32" fill="#6B4FBB" opacity=".5" rx="1.5"/></g></g></svg>
---
title: Added merge requests empty state
merge_request: 7342
author:
---
title: Removed the duplicated search icon in the award emoji menu
merge_request:
author:
---
title: Skip groups validation on the client
merge_request:
author:
...@@ -326,3 +326,21 @@ ...@@ -326,3 +326,21 @@
:why: https://github.com/domenic/opener/blob/1.4.3/LICENSE.txt :why: https://github.com/domenic/opener/blob/1.4.3/LICENSE.txt
:versions: [] :versions: []
:when: 2017-02-21 22:33:41.729629000 Z :when: 2017-02-21 22:33:41.729629000 Z
- - :approve
- jszip
- :who: Phil Hughes
:why: https://github.com/Stuk/jszip/blob/master/LICENSE.markdown
:versions: []
:when: 2017-04-05 10:38:46.275721000 Z
- - :approve
- jszip-utils
- :who: Phil Hughes
:why: https://github.com/Stuk/jszip-utils/blob/master/LICENSE.markdown
:versions: []
:when: 2017-04-05 10:39:32.676232000 Z
- - :approve
- pako
- :who: Phil Hughes
:why: https://github.com/nodeca/pako/blob/master/LICENSE
:versions: []
:when: 2017-04-05 10:43:45.897720000 Z
...@@ -37,6 +37,8 @@ var config = { ...@@ -37,6 +37,8 @@ var config = {
monitoring: './monitoring/monitoring_bundle.js', monitoring: './monitoring/monitoring_bundle.js',
network: './network/network_bundle.js', network: './network/network_bundle.js',
notebook_viewer: './blob/notebook_viewer.js', notebook_viewer: './blob/notebook_viewer.js',
sketch_viewer: './blob/sketch_viewer.js',
pdf_viewer: './blob/pdf_viewer.js',
profile: './profile/profile_bundle.js', profile: './profile/profile_bundle.js',
protected_branches: './protected_branches/protected_branches_bundle.js', protected_branches: './protected_branches/protected_branches_bundle.js',
snippet: './snippet/snippet_bundle.js', snippet: './snippet/snippet_bundle.js',
...@@ -64,7 +66,11 @@ var config = { ...@@ -64,7 +66,11 @@ var config = {
{ {
test: /\.svg$/, test: /\.svg$/,
use: 'raw-loader' use: 'raw-loader'
} }, {
test: /\.(worker.js|pdf)$/,
exclude: /node_modules/,
loader: 'file-loader',
},
] ]
}, },
...@@ -106,6 +112,7 @@ var config = { ...@@ -106,6 +112,7 @@ var config = {
'issuable', 'issuable',
'merge_conflicts', 'merge_conflicts',
'notebook_viewer', 'notebook_viewer',
'pdf_viewer',
'vue_pipelines', 'vue_pipelines',
], ],
minChunks: function(module, count) { minChunks: function(module, count) {
......
...@@ -39,6 +39,12 @@ Instead you should use polling mechanism with ETag caching in Redis. ...@@ -39,6 +39,12 @@ Instead you should use polling mechanism with ETag caching in Redis.
1. If the `If-None-Match` header does not match the current value in Redis 1. If the `If-None-Match` header does not match the current value in Redis
we have to generate a new response, because the resource changed. we have to generate a new response, because the resource changed.
Do not use query parameters (for example `?scope=all`) for endpoints where you
want to enable ETag caching. The middleware takes into account only the request
path and ignores query parameters. All parameters should be included in the
request path. By doing this we avoid query parameter ordering problems and make
route matching easier.
For more information see: For more information see:
- [RFC 7232](https://tools.ietf.org/html/rfc7232) - [RFC 7232](https://tools.ietf.org/html/rfc7232)
- [ETag proposal](https://gitlab.com/gitlab-org/gitlab-ce/issues/26926) - [ETag proposal](https://gitlab.com/gitlab-org/gitlab-ce/issues/26926)
...@@ -63,7 +63,8 @@ Feature: Dashboard ...@@ -63,7 +63,8 @@ Feature: Dashboard
@javascript @javascript
Scenario: Visiting Project's merge requests after sorting Scenario: Visiting Project's merge requests after sorting
Given I visit dashboard merge requests page Given project "Shop" has a "Bugfix MR" merge request open
And I visit dashboard merge requests page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit project "Shop" merge requests page And I visit project "Shop" merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
...@@ -56,14 +56,16 @@ Feature: Project Issues ...@@ -56,14 +56,16 @@ Feature: Project Issues
@javascript @javascript
Scenario: Visiting Merge Requests after being sorted the list Scenario: Visiting Merge Requests after being sorted the list
Given I visit project "Shop" issues page Given project "Shop" has a "Bugfix MR" merge request open
And I visit project "Shop" issues page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit project "Shop" merge requests page And I visit project "Shop" merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
@javascript @javascript
Scenario: Visiting Merge Requests from a differente Project after sorting Scenario: Visiting Merge Requests from a differente Project after sorting
Given I visit project "Shop" merge requests page Given project "Shop" has a "Bugfix MR" merge request open
And I visit project "Shop" merge requests page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit dashboard merge requests page And I visit dashboard merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
......
...@@ -42,8 +42,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps ...@@ -42,8 +42,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
end end
step 'I click link "New merge request"' do step 'I click link "New merge request"' do
expect(page).to have_content(/new merge request/i) page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
click_link "New Merge Request"
end end
step 'I should see the new merge request page for my namespace' do step 'I should see the new merge request page for my namespace' do
......
...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end end
step 'I click link "New Merge Request"' do step 'I click link "New Merge Request"' do
click_link "New Merge Request" page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
end end
step 'I should see merge request "Merge Request On Forked Project"' do step 'I should see merge request "Merge Request On Forked Project"' do
......
...@@ -24,7 +24,9 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps ...@@ -24,7 +24,9 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
step 'I click to emoji in the picker' do step 'I click to emoji in the picker' do
page.within '.emoji-menu-content' do page.within '.emoji-menu-content' do
page.first('.js-emoji-btn').click emoji_button = page.first('.js-emoji-btn')
emoji_button.hover
emoji_button.click
end end
end end
......
...@@ -14,7 +14,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps ...@@ -14,7 +14,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end end
step 'I click link "New Merge Request"' do step 'I click link "New Merge Request"' do
click_link "New Merge Request" page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
end end
step 'I click link "Bug NS-04"' do step 'I click link "Bug NS-04"' do
......
...@@ -273,6 +273,10 @@ module SharedProject ...@@ -273,6 +273,10 @@ module SharedProject
@project.update(public_builds: false) @project.update(public_builds: false)
end end
step 'project "Shop" has a "Bugfix MR" merge request open' do
create(:merge_request, title: "Bugfix MR", target_project: project, source_project: project, author: project.users.first)
end
def user_owns_project(user_name:, project_name:, visibility: :private) def user_owns_project(user_name:, project_name:, visibility: :private)
user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore) user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore)
project = Project.find_by(name: project_name) project = Project.find_by(name: project_name)
......
module Gitlab module Gitlab
module EtagCaching module EtagCaching
class Middleware class Middleware
RESERVED_WORDS = ProjectPathValidator::RESERVED.map { |word| "/#{word}/" }.join('|') RESERVED_WORDS = NamespaceValidator::WILDCARD_ROUTES.map { |word| "/#{word}/" }.join('|')
ROUTE_REGEXP = Regexp.union( ROUTE_REGEXP = Regexp.union(
%r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z) %r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z)
) )
......
require 'spec_helper'
describe 'Dashboard Merge Requests' do
let(:current_user) { create :user }
let(:project) do
create(:empty_project) do |project|
project.add_master(current_user)
end
end
before do
login_as(current_user)
end
it 'should show an empty state' do
visit merge_requests_dashboard_path(assignee_id: current_user.id)
expect(page).to have_selector('.empty-state')
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: current_user, source_project: project)
visit merge_requests_dashboard_path(assignee_id: current_user.id)
end
it 'should not show an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
end
require 'spec_helper'
feature 'Groups Merge Requests Empty States' do
let(:group) { create(:group) }
let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
before do
login_as(user)
end
context 'group has a project' do
let(:project) { create(:empty_project, namespace: group) }
before do
project.add_master(user)
end
context 'the project has a merge request' do
before do
create(:merge_request, source_project: project)
visit merge_requests_group_path(group)
end
it 'should not display an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
context 'the project has no merge requests', :js do
before do
visit merge_requests_group_path(group)
end
it 'should display an empty state' do
expect(page).to have_selector('.empty-state')
end
it 'should show a new merge request button' do
within '.empty-state' do
expect(page).to have_content('New merge request')
end
end
it 'the new merge request button opens a project dropdown' do
within '.empty-state' do
find('.new-project-item-select-button').click
end
expect(page).to have_selector('.ajax-project-dropdown')
end
end
end
context 'group without a project' do
before do
visit merge_requests_group_path(group)
end
it 'should display an empty state' do
expect(page).to have_selector('.empty-state')
end
it 'should not show a new merge request button' do
within '.empty-state' do
expect(page).not_to have_link('New merge request')
end
end
end
end
...@@ -15,7 +15,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -15,7 +15,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'selects the source branch sha when a tag with the same name exists' do it 'selects the source branch sha when a tag with the same name exists' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' click_link 'New merge request'
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
...@@ -27,8 +27,8 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -27,8 +27,8 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'selects the target branch sha when a tag with the same name exists' do it 'selects the target branch sha when a tag with the same name exists' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' click_link 'New merge request'
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
...@@ -42,7 +42,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -42,7 +42,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'generates a diff for an orphaned branch' do it 'generates a diff for an orphaned branch' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
......
...@@ -17,4 +17,28 @@ feature 'Merge Requests List' do ...@@ -17,4 +17,28 @@ feature 'Merge Requests List' do
expect(page).not_to have_selector('.js-new-board-list') expect(page).not_to have_selector('.js-new-board-list')
end end
it 'should show an empty state' do
visit namespace_project_merge_requests_path(project.namespace, project)
expect(page).to have_selector('.empty-state')
end
it 'empty state should have a create merge request button' do
visit namespace_project_merge_requests_path(project.namespace, project)
expect(page).to have_link 'New merge request', href: new_namespace_project_merge_request_path(project.namespace, project)
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: user, source_project: project)
visit namespace_project_merge_requests_path(project.namespace, project)
end
it 'should not show an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
end end
...@@ -164,6 +164,8 @@ describe "Search", feature: true do ...@@ -164,6 +164,8 @@ describe "Search", feature: true do
end end
context 'click the links in the category search dropdown', js: true do context 'click the links in the category search dropdown', js: true do
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignee: user) }
before do before do
page.find('#search').click page.find('#search').click
end end
......
import renderPDF from '~/blob/pdf';
import testPDF from './test.pdf';
describe('PDF renderer', () => {
let viewer;
preloadFixtures('static/pdf_viewer.html.raw');
beforeEach(() => {
loadFixtures('static/pdf_viewer.html.raw');
viewer = document.getElementById('js-pdf-viewer');
viewer.dataset.endpoint = testPDF;
});
it('shows loading icon', () => {
renderPDF();
expect(
document.querySelector('.loading'),
).not.toBeNull();
});
describe('successful response', () => {
beforeEach((done) => {
renderPDF();
setTimeout(() => {
done();
}, 500);
});
it('does not show loading icon', () => {
expect(
document.querySelector('.loading'),
).toBeNull();
});
it('renders the PDF', () => {
expect(
document.querySelector('.pdf-viewer'),
).not.toBeNull();
});
it('renders the PDF page', () => {
expect(
document.querySelector('.pdf-page'),
).not.toBeNull();
});
});
describe('error getting file', () => {
beforeEach((done) => {
viewer.dataset.endpoint = 'invalid/endpoint';
renderPDF();
setTimeout(() => {
done();
}, 500);
});
it('does not show loading icon', () => {
expect(
document.querySelector('.loading'),
).toBeNull();
});
it('shows error message', () => {
expect(
document.querySelector('.md').textContent.trim(),
).toBe('An error occured whilst loading the file. Please try again later.');
});
});
});
/* eslint-disable no-new */
import JSZip from 'jszip';
import SketchLoader from '~/blob/sketch';
describe('Sketch viewer', () => {
const generateZipFileArrayBuffer = (zipFile, resolve, done) => {
zipFile
.generateAsync({ type: 'arrayBuffer' })
.then((content) => {
resolve(content);
setTimeout(() => {
done();
}, 100);
});
};
preloadFixtures('static/sketch_viewer.html.raw');
beforeEach(() => {
loadFixtures('static/sketch_viewer.html.raw');
});
describe('with error message', () => {
beforeEach((done) => {
spyOn(SketchLoader.prototype, 'getZipFile').and.callFake(() => new Promise((resolve, reject) => {
reject();
setTimeout(() => {
done();
});
}));
new SketchLoader(document.getElementById('js-sketch-viewer'));
});
it('renders error message', () => {
expect(
document.querySelector('#js-sketch-viewer p'),
).not.toBeNull();
expect(
document.querySelector('#js-sketch-viewer p').textContent.trim(),
).toContain('Cannot show preview.');
});
it('removes render the loading icon', () => {
expect(
document.querySelector('.js-loading-icon'),
).toBeNull();
});
});
describe('success', () => {
beforeEach((done) => {
spyOn(SketchLoader.prototype, 'getZipFile').and.callFake(() => new Promise((resolve) => {
const zipFile = new JSZip();
zipFile.folder('previews')
.file('preview.png', 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA1JREFUeNoBAgD9/wAAAAIAAVMrnDAAAAAASUVORK5CYII=', {
base64: true,
});
generateZipFileArrayBuffer(zipFile, resolve, done);
}));
new SketchLoader(document.getElementById('js-sketch-viewer'));
});
it('does not render error message', () => {
expect(
document.querySelector('#js-sketch-viewer p'),
).toBeNull();
});
it('removes render the loading icon', () => {
expect(
document.querySelector('.js-loading-icon'),
).toBeNull();
});
it('renders preview img', () => {
const img = document.querySelector('#js-sketch-viewer img');
expect(img).not.toBeNull();
expect(img.classList.contains('img-responsive')).toBeTruthy();
});
it('renders link to image', () => {
const img = document.querySelector('#js-sketch-viewer img');
const link = document.querySelector('#js-sketch-viewer a');
expect(link.href).toBe(img.src);
expect(link.target).toBe('_blank');
});
});
describe('incorrect file', () => {
beforeEach((done) => {
spyOn(SketchLoader.prototype, 'getZipFile').and.callFake(() => new Promise((resolve) => {
const zipFile = new JSZip();
generateZipFileArrayBuffer(zipFile, resolve, done);
}));
new SketchLoader(document.getElementById('js-sketch-viewer'));
});
it('renders error message', () => {
expect(
document.querySelector('#js-sketch-viewer p'),
).not.toBeNull();
expect(
document.querySelector('#js-sketch-viewer p').textContent.trim(),
).toContain('Cannot show preview.');
});
});
});
.file-content#js-pdf-viewer{ data: { endpoint: '/test' } }
.file-content#js-sketch-viewer{ data: { endpoint: '/test_sketch_file.sketch' } }
.js-loading-icon
...@@ -53,6 +53,20 @@ describe Blob do ...@@ -53,6 +53,20 @@ describe Blob do
end end
end end
describe '#pdf?' do
it 'is falsey when file extension is not .pdf' do
git_blob = double(name: 'git_blob.txt')
expect(described_class.decorate(git_blob)).not_to be_pdf
end
it 'is truthy when file extension is .pdf' do
git_blob = double(name: 'git_blob.pdf')
expect(described_class.decorate(git_blob)).to be_pdf
end
end
describe '#ipython_notebook?' do describe '#ipython_notebook?' do
it 'is falsey when language is not Jupyter Notebook' do it 'is falsey when language is not Jupyter Notebook' do
git_blob = double(text?: true, language: double(name: 'JSON')) git_blob = double(text?: true, language: double(name: 'JSON'))
...@@ -67,6 +81,20 @@ describe Blob do ...@@ -67,6 +81,20 @@ describe Blob do
end end
end end
describe '#sketch?' do
it 'is falsey with image extension' do
git_blob = Gitlab::Git::Blob.new(name: "design.png")
expect(described_class.decorate(git_blob)).not_to be_sketch
end
it 'is truthy with sketch extension' do
git_blob = Gitlab::Git::Blob.new(name: "design.sketch")
expect(described_class.decorate(git_blob)).to be_sketch
end
end
describe '#video?' do describe '#video?' do
it 'is falsey with image extension' do it 'is falsey with image extension' do
git_blob = Gitlab::Git::Blob.new(name: 'image.png') git_blob = Gitlab::Git::Blob.new(name: 'image.png')
...@@ -88,11 +116,13 @@ describe Blob do ...@@ -88,11 +116,13 @@ describe Blob do
def stubbed_blob(overrides = {}) def stubbed_blob(overrides = {})
overrides.reverse_merge!( overrides.reverse_merge!(
name: nil,
image?: false, image?: false,
language: nil, language: nil,
lfs_pointer?: false, lfs_pointer?: false,
svg?: false, svg?: false,
text?: false text?: false,
binary?: false
) )
described_class.decorate(double).tap do |blob| described_class.decorate(double).tap do |blob|
...@@ -131,10 +161,20 @@ describe Blob do ...@@ -131,10 +161,20 @@ describe Blob do
expect(blob.to_partial_path(project)).to eq 'download' expect(blob.to_partial_path(project)).to eq 'download'
end end
it 'handles PDFs' do
blob = stubbed_blob(name: 'blob.pdf', pdf?: true)
expect(blob.to_partial_path(project)).to eq 'pdf'
end
it 'handles iPython notebooks' do it 'handles iPython notebooks' do
blob = stubbed_blob(text?: true, ipython_notebook?: true) blob = stubbed_blob(text?: true, ipython_notebook?: true)
expect(blob.to_partial_path(project)).to eq 'notebook' expect(blob.to_partial_path(project)).to eq 'notebook'
end end
it 'handles Sketch files' do
blob = stubbed_blob(text?: true, sketch?: true, binary?: true)
expect(blob.to_partial_path(project)).to eq 'sketch'
end
end end
describe '#size_within_svg_limits?' do describe '#size_within_svg_limits?' do
......
This diff is collapsed.
This diff is collapsed.
...@@ -1255,6 +1255,10 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: ...@@ -1255,6 +1255,10 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
core-js@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65"
core-util-is@~1.0.0: core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
...@@ -1611,6 +1615,10 @@ es6-map@^0.1.3: ...@@ -1611,6 +1615,10 @@ es6-map@^0.1.3:
es6-symbol "~3.1.1" es6-symbol "~3.1.1"
event-emitter "~0.3.5" event-emitter "~0.3.5"
es6-promise@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6"
es6-promise@~4.0.3: es6-promise@~4.0.3:
version "4.0.5" version "4.0.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42"
...@@ -1973,6 +1981,12 @@ file-entry-cache@^2.0.0: ...@@ -1973,6 +1981,12 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1" flat-cache "^1.2.1"
object-assign "^4.0.1" object-assign "^4.0.1"
file-loader@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.1.tgz#6b328ee1234a729e4e47d36375dd6d35c0e1db84"
dependencies:
loader-utils "^1.0.2"
filename-regex@^2.0.0: filename-regex@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
...@@ -2405,6 +2419,10 @@ ignore@^3.2.0: ...@@ -2405,6 +2419,10 @@ ignore@^3.2.0:
version "3.2.6" version "3.2.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c"
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
imurmurhash@^0.1.4: imurmurhash@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
...@@ -2833,6 +2851,20 @@ jsprim@^1.2.2: ...@@ -2833,6 +2851,20 @@ jsprim@^1.2.2:
json-schema "0.2.3" json-schema "0.2.3"
verror "1.3.6" verror "1.3.6"
jszip-utils@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/jszip-utils/-/jszip-utils-0.0.2.tgz#457d5cbca60a1c2e0706e9da2b544e8e7bc50bf8"
jszip@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.3.tgz#8a920403b2b1651c0fc126be90192d9080957c37"
dependencies:
core-js "~2.3.0"
es6-promise "~3.0.2"
lie "~3.1.0"
pako "~1.0.2"
readable-stream "~2.0.6"
karma-coverage-istanbul-reporter@^0.2.0: karma-coverage-istanbul-reporter@^0.2.0:
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-0.2.3.tgz#11f1be9cfa93755a77bac39ab16e315a7100b5c5" resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-0.2.3.tgz#11f1be9cfa93755a77bac39ab16e315a7100b5c5"
...@@ -2937,6 +2969,12 @@ levn@^0.3.0, levn@~0.3.0: ...@@ -2937,6 +2969,12 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2" prelude-ls "~1.1.2"
type-check "~0.3.2" type-check "~0.3.2"
lie@~3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
dependencies:
immediate "~3.0.5"
load-json-file@^1.0.0: load-json-file@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
...@@ -2960,6 +2998,14 @@ loader-utils@^0.2.16, loader-utils@^0.2.5: ...@@ -2960,6 +2998,14 @@ loader-utils@^0.2.16, loader-utils@^0.2.5:
json5 "^0.5.0" json5 "^0.5.0"
object-assign "^4.0.1" object-assign "^4.0.1"
loader-utils@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
dependencies:
big.js "^3.1.3"
emojis-list "^2.0.0"
json5 "^0.5.0"
locate-path@^2.0.0: locate-path@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
...@@ -3432,6 +3478,10 @@ pako@~0.2.0: ...@@ -3432,6 +3478,10 @@ pako@~0.2.0:
version "0.2.9" version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
pako@~1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.5.tgz#d2205dfe5b9da8af797e7c163db4d1f84e4600bc"
parse-asn1@^5.0.0: parse-asn1@^5.0.0:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
...@@ -3744,7 +3794,7 @@ readable-stream@~1.0.2: ...@@ -3744,7 +3794,7 @@ readable-stream@~1.0.2:
isarray "0.0.1" isarray "0.0.1"
string_decoder "~0.10.x" string_decoder "~0.10.x"
readable-stream@~2.0.0: readable-stream@~2.0.0, readable-stream@~2.0.6:
version "2.0.6" version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies: dependencies:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment