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:
commit
cdb4424ec0
9 changed files with 173 additions and 5 deletions
|
@ -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"
|
||||||
|
|
|
@ -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>
|
|
@ -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; }
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Add Join meeting button to issues with Zoom links
|
||||||
|
merge_request: 29454
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -5597,6 +5597,9 @@ msgstr ""
|
||||||
msgid "Job|with"
|
msgid "Job|with"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Join Zoom meeting"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Jul"
|
msgid "Jul"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
91
spec/frontend/issue_show/components/pinned_links_spec.js
Normal file
91
spec/frontend/issue_show/components/pinned_links_spec.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue