Merge branch '62966-embed-zoom-call-in-issue-mvc' into 'master'

Resolve "Embed Zoom Call in Issue MVC"

Closes #62966

See merge request gitlab-org/gitlab-ce!29454
This commit is contained in:
Kushal Pandya 2019-06-14 16:01:48 +00:00
commit cdb4424ec0
9 changed files with 173 additions and 5 deletions

View File

@ -11,6 +11,7 @@ import titleComponent from './title.vue';
import descriptionComponent from './description.vue'; import descriptionComponent from './description.vue';
import editedComponent from './edited.vue'; import editedComponent from './edited.vue';
import formComponent from './form.vue'; import formComponent from './form.vue';
import PinnedLinks from './pinned_links.vue';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default { export default {
@ -19,6 +20,7 @@ export default {
titleComponent, titleComponent,
editedComponent, editedComponent,
formComponent, formComponent,
PinnedLinks,
}, },
mixins: [recaptchaModalImplementor], mixins: [recaptchaModalImplementor],
props: { props: {
@ -340,6 +342,7 @@ export default {
:title-text="state.titleText" :title-text="state.titleText"
:show-inline-edit-button="showInlineEditButton" :show-inline-edit-button="showInlineEditButton"
/> />
<pinned-links :description-html="state.descriptionHtml" />
<description-component <description-component
v-if="state.descriptionHtml" v-if="state.descriptionHtml"
:can-update="canUpdate" :can-update="canUpdate"

View File

@ -0,0 +1,52 @@
<script>
import { GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
Icon,
GlLink,
},
props: {
descriptionHtml: {
type: String,
required: true,
},
},
computed: {
linksInDescription() {
const el = document.createElement('div');
el.innerHTML = this.descriptionHtml;
return [...el.querySelectorAll('a')].map(a => a.href);
},
// Detect links matching the following formats:
// Zoom Start links: https://zoom.us/s/<meeting-id>
// Zoom Join links: https://zoom.us/j/<meeting-id>
// Personal Zoom links: https://zoom.us/my/<meeting-id>
// Vanity Zoom links: https://gitlab.zoom.us/j/<meeting-id> (also /s and /my)
zoomHref() {
const zoomRegex = /^https:\/\/([\w\d-]+\.)?zoom\.us\/(s|j|my)\/.+/;
return this.linksInDescription.reduce((acc, currentLink) => {
let lastLink = acc;
if (zoomRegex.test(currentLink)) {
lastLink = currentLink;
}
return lastLink;
}, '');
},
},
};
</script>
<template>
<div v-if="zoomHref" class="border-bottom mb-3 mt-n2">
<gl-link
:href="zoomHref"
target="_blank"
class="btn btn-inverted btn-secondary btn-sm text-dark mb-3"
>
<icon name="brand-zoom" :size="14" />
<strong class="vertical-align-top">{{ __('Join Zoom meeting') }}</strong>
</gl-link>
</div>
</template>

View File

@ -416,6 +416,7 @@ img.emoji {
.center { text-align: center; } .center { text-align: center; }
.block { display: block; } .block { display: block; }
.flex { display: flex; } .flex { display: flex; }
.vertical-align-top { vertical-align: top; }
.vertical-align-middle { vertical-align: middle; } .vertical-align-middle { vertical-align: middle; }
.vertical-align-sub { vertical-align: sub; } .vertical-align-sub { vertical-align: sub; }
.flex-align-self-center { align-self: center; } .flex-align-self-center { align-self: center; }

View File

@ -0,0 +1,5 @@
---
title: Add Join meeting button to issues with Zoom links
merge_request: 29454
author:
type: added

View File

@ -5597,6 +5597,9 @@ msgstr ""
msgid "Job|with" msgid "Job|with"
msgstr "" msgstr ""
msgid "Join Zoom meeting"
msgstr ""
msgid "Jul" msgid "Jul"
msgstr "" msgstr ""

View File

@ -37,7 +37,7 @@
"@babel/plugin-syntax-import-meta": "^7.2.0", "@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.4.4", "@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0", "@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.63.0", "@gitlab/svgs": "^1.64.0",
"@gitlab/ui": "^4.0.0", "@gitlab/ui": "^4.0.0",
"apollo-cache-inmemory": "^1.5.1", "apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1", "apollo-client": "^2.5.1",

View File

@ -92,6 +92,19 @@ describe "User creates issue" do
.and have_content(label_titles.first) .and have_content(label_titles.first)
end end
end end
context "with Zoom link" do
it "adds Zoom button" do
issue_title = "Issue containing Zoom meeting link"
zoom_url = "https://gitlab.zoom.us/j/123456789"
fill_in("Title", with: issue_title)
fill_in("Description", with: zoom_url)
click_button("Submit issue")
expect(page).to have_link('Join Zoom meeting', href: zoom_url)
end
end
end end
context "when signed in as user with special characters in their name" do context "when signed in as user with special characters in their name" do

View File

@ -0,0 +1,91 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import PinnedLinks from '~/issue_show/components/pinned_links.vue';
const localVue = createLocalVue();
const plainZoomUrl = 'https://zoom.us/j/123456789';
const vanityZoomUrl = 'https://gitlab.zoom.us/j/123456789';
const startZoomUrl = 'https://zoom.us/s/123456789';
const personalZoomUrl = 'https://zoom.us/my/hunter-zoloman';
const randomUrl = 'https://zoom.us.com';
describe('PinnedLinks', () => {
let wrapper;
const link = {
get text() {
return wrapper.find(GlLink).text();
},
get href() {
return wrapper.find(GlLink).attributes('href');
},
};
const createComponent = props => {
wrapper = shallowMount(localVue.extend(PinnedLinks), {
localVue,
sync: false,
propsData: {
descriptionHtml: '',
...props,
},
});
};
it('displays Zoom link', () => {
createComponent({
descriptionHtml: `<a href="${plainZoomUrl}">Zoom</a>`,
});
expect(link.text).toBe('Join Zoom meeting');
});
it('detects plain Zoom link', () => {
createComponent({
descriptionHtml: `<a href="${plainZoomUrl}">Zoom</a>`,
});
expect(link.href).toBe(plainZoomUrl);
});
it('detects vanity Zoom link', () => {
createComponent({
descriptionHtml: `<a href="${vanityZoomUrl}">Zoom</a>`,
});
expect(link.href).toBe(vanityZoomUrl);
});
it('detects Zoom start meeting link', () => {
createComponent({
descriptionHtml: `<a href="${startZoomUrl}">Zoom</a>`,
});
expect(link.href).toBe(startZoomUrl);
});
it('detects personal Zoom room link', () => {
createComponent({
descriptionHtml: `<a href="${personalZoomUrl}">Zoom</a>`,
});
expect(link.href).toBe(personalZoomUrl);
});
it('only renders final Zoom link in description', () => {
createComponent({
descriptionHtml: `<a href="${plainZoomUrl}">Zoom</a><a href="${vanityZoomUrl}">Zoom</a>`,
});
expect(link.href).toBe(vanityZoomUrl);
});
it('does not render for other links', () => {
createComponent({
descriptionHtml: `<a href="${randomUrl}">Some other link</a>`,
});
expect(wrapper.find(GlLink).exists()).toBe(false);
});
});

View File

@ -700,10 +700,10 @@
dependencies: dependencies:
requireindex "~1.1.0" requireindex "~1.1.0"
"@gitlab/svgs@^1.63.0": "@gitlab/svgs@^1.64.0":
version "1.63.0" version "1.64.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.63.0.tgz#9dd544026d203e4ce6efed72b05db68f710c4d49" resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.64.0.tgz#1370bcbe9ca0ecc9fb919956cd4241bea090ddd3"
integrity sha512-YztrReFTg31B7v5wtUC5j15KHNcMebtW+kACytEU42XomMaIwk4USIbygqWlq0VRHA2VHJrHApfJHIjxiCCQcA== integrity sha512-y9p73NGDnQJc18Dtk0oJfgxedancBT6UceATcnZMceLV6iWylzdMbQWxCl4O2aBXwsAoCrLUJQ9jhRkbNicYNA==
"@gitlab/ui@^4.0.0": "@gitlab/ui@^4.0.0":
version "4.0.0" version "4.0.0"