From d36869d14781b1c97bb069bde1f00ec23c5ac9db Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Mon, 6 May 2019 20:18:48 +0100 Subject: Build visual_review_toolbar with webpack It takes a lot of lines to move a script --- .../javascripts/visual_review_toolbar/index.js | 792 +++++++++++++++++++++ config/karma.config.js | 2 +- config/webpack.config.js | 60 +- public/visual-review-toolbar.js | 198 +++++- 4 files changed, 1026 insertions(+), 26 deletions(-) create mode 100644 app/assets/javascripts/visual_review_toolbar/index.js diff --git a/app/assets/javascripts/visual_review_toolbar/index.js b/app/assets/javascripts/visual_review_toolbar/index.js new file mode 100644 index 00000000000..0a9e497c3cf --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/index.js @@ -0,0 +1,792 @@ +/////////////////////////////////////////////// +/////////////////// STYLES //////////////////// +/////////////////////////////////////////////// + +const buttonClearStyles = ` + -webkit-appearance: none; +`; + +const buttonBaseStyles = ` + cursor: pointer; + transition: background-color 100ms linear, border-color 100ms linear, color 100ms linear, box-shadow 100ms linear; +`; + +const buttonSuccessActiveStyles = ` + background-color: #168f48; + border-color: #12753a; + color: #fff; +`; + +const buttonSuccessHoverStyles = ` + color: #fff; + background-color: #137e3f; + border-color: #127339; +`; + +const buttonSuccessStyles = ` + ${buttonBaseStyles} + background-color: #1aaa55; + border: 1px solid #168f48; + color: #fff; +`; + +const buttonSecondaryStyles = ` + ${buttonBaseStyles} + background: none #fff; + margin: 0 .5rem; + border: 1px solid #e3e3e3; +`; + +const buttonSecondaryActiveStyles = ` + color: #2e2e2e; + background-color: #e1e1e1; + border-color: #dadada; +`; + +const buttonSecondaryHoverStyles = ` + background-color: #f0f0f0; + border-color: #e3e3e3; + color: #2e2e2e; +`; + +const buttonWideStyles = ` + width: 100%; +`; + +const buttonWrapperStyles = ` + margin-top: 1rem; + display: flex; + align-items: baseline; + justify-content: flex-end; +`; + +const collapseStyles = ` + ${buttonBaseStyles} + width: 2.4rem; + height: 2.2rem; + margin-left: 1rem; + padding: .5rem; +`; + +const collapseClosedStyles = ` + ${collapseStyles} + align-self: center; +`; + +const collapseOpenStyles = ` + ${collapseStyles} +`; + +const checkboxLabelStyles = ` + padding: 0 .2rem; +`; + +const checkboxWrapperStyles = ` + display: flex; + align-items: baseline; +`; + +const formStyles = ` + display: flex; + flex-direction: column; + width: 100% +`; + +const labelStyles = ` + font-weight: 600; + display: inline-block; + width: 100%; +`; + +const linkStyles = ` + color: #1b69b6; + text-decoration: none; + background-color: transparent; + background-image: none; +`; + +const messageStyles = ` + padding: .25rem 0; + margin: 0; + line-height: 1.2rem; +`; + +const metadataNoteStyles = ` + font-size: .7rem; + line-height: 1rem; + color: #666; + margin-bottom: 0; +`; + +const inputStyles = ` + width: 100%; + border: 1px solid #dfdfdf; + border-radius: 4px; + padding: .1rem .2rem; + min-height: 2rem; + max-width: 17rem; +`; + +const svgInnerStyles = ` + pointer-events: none; +`; + +const wrapperClosedStyles = ` + max-width: 3.4rem; + max-height: 3.4rem; +`; + +const wrapperOpenStyles = ` + max-width: 22rem; + max-height: 22rem; +`; + +const wrapperStyles = ` + max-width: 22rem; + max-height: 22rem; + overflow: scroll; + position: fixed; + bottom: 1rem; + right: 1rem; + display: flex; + flex-direction: row-reverse; + padding: 1rem; + background-color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, + 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + font-size: .8rem; + font-weight: 400; + color: #2e2e2e; +`; + +const gitlabStyles = ` + #gitlab-collapse > * { + ${svgInnerStyles} + } + + #gitlab-form-wrapper { + ${formStyles} + } + + #gitlab-review-container { + ${wrapperStyles} + } + + .gitlab-open-wrapper { + ${wrapperOpenStyles} + } + + .gitlab-closed-wrapper { + ${wrapperClosedStyles} + } + + .gitlab-button-secondary { + ${buttonSecondaryStyles} + } + + .gitlab-button-secondary:hover { + ${buttonSecondaryHoverStyles} + } + + .gitlab-button-secondary:active { + ${buttonSecondaryActiveStyles} + } + + .gitlab-button-success:hover { + ${buttonSuccessHoverStyles} + } + + .gitlab-button-success:active { + ${buttonSuccessActiveStyles} + } + + .gitlab-button-success { + ${buttonSuccessStyles} + } + + .gitlab-button-wide { + ${buttonWideStyles} + } + + .gitlab-button-wrapper { + ${buttonWrapperStyles} + } + + .gitlab-collapse-closed { + ${collapseClosedStyles} + } + + .gitlab-collapse-open { + ${collapseOpenStyles} + } + + .gitlab-checkbox-label { + ${checkboxLabelStyles} + } + + .gitlab-checkbox-wrapper { + ${checkboxWrapperStyles} + } + + .gitlab-label { + ${labelStyles} + } + + .gitlab-link { + ${linkStyles} + } + + .gitlab-message { + ${messageStyles} + } + + .gitlab-metadata-note { + ${metadataNoteStyles} + } + + .gitlab-input { + ${inputStyles} + } +`; + +function addStylesheet() { + const styleEl = document.createElement('style'); + styleEl.insertAdjacentHTML('beforeend', gitlabStyles); + document.head.appendChild(styleEl); +} + +/////////////////////////////////////////////// +/////////////////// STATE //////////////////// +/////////////////////////////////////////////// +const data = {}; + +/////////////////////////////////////////////// +///////////////// COMPONENTS ////////////////// +/////////////////////////////////////////////// +const note = ` +

+`; + +const comment = ` +
+ + ${note} + +
+
+ + +
+`; + +const commentIcon = ` +<<<<<<< HEAD:public/visual-review-toolbar.js + icn/comment +` +======= + icn/comment +`; +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + +const compressIcon = ` + icn/compress +`; + +const collapseButton = ` + +`; + +const form = content => ` +
+ ${content} +
+`; + +const login = ` +
+ + + ${note} +
+
+ + +
+
+ +
+`; + +/////////////////////////////////////////////// +//////////////// INTERACTIONS ///////////////// +/////////////////////////////////////////////// + +// from https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator +function getBrowserId(sUsrAg) { + var aKeys = ['MSIE', 'Edge', 'Firefox', 'Safari', 'Chrome', 'Opera'], + nIdx = aKeys.length - 1; + + for (nIdx; nIdx > -1 && sUsrAg.indexOf(aKeys[nIdx]) === -1; nIdx--); + return aKeys[nIdx]; +} + +<<<<<<< HEAD:public/visual-review-toolbar.js +function addCommentForm () { + const formWrapper = document.getElementById('gitlab-form-wrapper'); + formWrapper.innerHTML = comment; +======= +function addCommentButtonEvent() { + // get user agent data + const { + innerWidth, + innerHeight, + location: { href }, + navigator: { platform, userAgent }, + } = window; + const browser = getBrowserId(userAgent); + + const scriptName = 'ReviewAppToolbar'; + const projectId = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-project'); + const discussionId = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-discussion'); + const mrUrl = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-mr-url'); + const commentButton = document.getElementById('gitlab-comment-button'); + + const details = { + href, + platform, + browser, + userAgent, + innerWidth, + innerHeight, + projectId, + discussionId, + mrUrl, + }; + + commentButton.onclick = postComment.bind(null, details); +} + +function addCollapseEvent() { + const collapseButton = document.getElementById('gitlab-collapse'); + collapseButton.onclick = collapseForm; +} + +function addCommentForm() { + const formWrapper = document.getElementById('gitlab-form-wrapper'); + formWrapper.innerHTML = comment; + removeButtonAndClickEvent('gitlab-login', authorizeUser); + addCommentButtonEvent(); + addLogoutButtonEvent(); +} + +function addLoginButtonEvent() { + const loginButton = document.getElementById('gitlab-login'); + if (loginButton) { + loginButton.onclick = authorizeUser; + } +} + +function addLogoutButtonEvent() { + const logoutButton = document.getElementById('gitlab-logout-button'); + if (logoutButton) { + logoutButton.onclick = logoutUser; + } +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js +} + +function addLoginForm() { + const formWrapper = document.getElementById('gitlab-form-wrapper'); + formWrapper.innerHTML = login; +} + +<<<<<<< HEAD:public/visual-review-toolbar.js +function authorizeUser () { +======= +function authorizeUser() { +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + // Clear any old errors + clearNote('gitlab-token'); + + const token = document.getElementById('gitlab-token').value; + const rememberMe = document.getElementById('remember_token').checked; + + if (!token) { + postError('Please enter your token.', 'gitlab-token'); + return; + } + + if (rememberMe) { + storeToken(token); + } + + authSuccess(token); + return; +} + +function authSuccess(token) { + data.token = token; + addCommentForm(); +} + +function clearNote(inputId) { + const note = document.getElementById('gitlab-validation-note'); + note.innerText = ''; + note.style.color = ''; + + if (inputId) { + const field = document.getElementById(inputId); + field.style.borderColor = ''; + } +} + +<<<<<<< HEAD:public/visual-review-toolbar.js +function confirmAndClear (mergeRequestId) { +======= +function confirmAndClear(discussionId) { +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + const commentButton = document.getElementById('gitlab-comment-button'); + const note = document.getElementById('gitlab-validation-note'); + + commentButton.innerText = 'Feedback sent'; + note.innerText = `Your comment was successfully posted to merge request #${mergeRequestId}`; + + setTimeout(resetCommentButton, 1000); +} + +<<<<<<< HEAD:public/visual-review-toolbar.js +function getInitialState () { + const { localStorage } = window; + + try { + let token = localStorage.getItem('token'); + + if (token) { + data.token = token; + return comment; + } + + return login; + + } catch (err) { + return login; + } +} + +function getProjectDetails () { + const { innerWidth, + innerHeight, + location: { href }, + navigator: { + platform, userAgent + } } = window; + const browser = getBrowserId(userAgent); +======= +function collapseForm() { + const container = document.getElementById('gitlab-review-container'); + const collapseButton = document.getElementById('gitlab-collapse'); + const form = document.getElementById('gitlab-form-wrapper'); + + container.classList.replace('gitlab-open-wrapper', 'gitlab-closed-wrapper'); + container.style.backgroundColor = 'rgba(255, 255, 255, 0)'; + form.style.display = 'none'; + + collapseButton.classList.replace('gitlab-collapse-open', 'gitlab-collapse-closed'); + collapseButton.innerHTML = commentIcon; + collapseButton.onclick = expandForm; +} + +function expandForm() { + const container = document.getElementById('gitlab-review-container'); + const collapseButton = document.getElementById('gitlab-collapse'); + const form = document.getElementById('gitlab-form-wrapper'); + + container.classList.replace('gitlab-closed-wrapper', 'gitlab-open-wrapper'); + container.style.backgroundColor = 'rgba(255, 255, 255, 1)'; + form.style.display = 'flex'; + + collapseButton.classList.replace('gitlab-collapse-closed', 'gitlab-collapse-open'); + collapseButton.innerHTML = compressIcon; + collapseButton.onclick = collapseForm; +} + +function getInitialState() { + const { localStorage } = window; + + if (!localStorage || !localStorage.getItem('token')) { + return { + content: login, + addEvent: addLoginButtonEvent, + }; + } +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + + const scriptEl = document.getElementById('review-app-toolbar-script') + const { projectId, mergeRequestId, mrUrl } = scriptEl.dataset; + + return { +<<<<<<< HEAD:public/visual-review-toolbar.js + href, + platform, + browser, + userAgent, + innerWidth, + innerHeight, + projectId, + mergeRequestId, + mrUrl, +======= + content: comment, + addEvent: () => { + addCommentButtonEvent(); + addLogoutButtonEvent(); + }, +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + }; +} + +function logoutUser() { + const { localStorage } = window; + + // All the browsers we support have localStorage, so let's silently fail + // and go on with the rest of the functionality. + try { + localStorage.removeItem('token'); + } catch (err) { + return; + } + + addLoginForm(); +} + +function postComment({ + href, + platform, + browser, + userAgent, + innerWidth, + innerHeight, + projectId, + mergeRequestId, + mrUrl, +}) { + // Clear any old errors + clearNote('gitlab-comment'); + + setInProgressState(); + + const commentText = document.getElementById('gitlab-comment').value.trim(); + + if (!commentText) { + postError('Your comment appears to be empty.', 'gitlab-comment'); + resetCommentBox(); + return; + } + + const detailText = ` +<<<<<<< HEAD:public/visual-review-toolbar.js + \n +
+ Metadata + Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. +

+ User agent: ${userAgent} +
+======= +
+ Metadata + Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. +

+ *User agent: ${userAgent}* +
+>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js + `; + + const url = ` + ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`; + + + const body = `${commentText} ${detailText}`; + + fetch(url, { + method: 'POST', + headers: { + 'PRIVATE-TOKEN': data.token, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ body }), + }) +<<<<<<< HEAD:public/visual-review-toolbar.js + .then((response) => { + if (response.ok) { + confirmAndClear(mergeRequestId); + return; + } + + throw new Error(`${response.status}: ${response.statusText}`) + }) + .catch((err) => { + postError(`The feedback was not sent successfully. Please try again. Error: ${err.message}`, 'gitlab-comment'); + resetCommentBox(); + }); +======= + .then(response => { + if (response.ok) { + confirmAndClear(discussionId); + return; + } + + throw new Error(`${response.status}: ${response.statusText}`); + }) + .catch(err => { + postError( + `The feedback was not sent successfully. Please try again. Error: ${err.message}`, + 'gitlab-comment', + ); + resetCommentBox(); + }); +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js +} + +function postError(message, inputId) { + const note = document.getElementById('gitlab-validation-note'); + const field = document.getElementById(inputId); + field.style.borderColor = '#db3b21'; + note.style.color = '#db3b21'; + note.innerText = message; +} + +<<<<<<< HEAD:public/visual-review-toolbar.js +======= +function removeButtonAndClickEvent(buttonId, eventListener) { + const button = document.getElementById(buttonId); + if (button) { + button.removeEventListener(eventListener); + } +} + +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js +function resetCommentBox() { + const commentBox = document.getElementById('gitlab-comment'); + const commentButton = document.getElementById('gitlab-comment-button'); + + commentButton.innerText = 'Send feedback'; + commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success'); + commentButton.style.opacity = 1; + + commentBox.style.pointerEvents = 'auto'; + commentBox.style.color = 'rgba(0, 0, 0, 1)'; +} + +function resetCommentButton() { + const commentBox = document.getElementById('gitlab-comment'); + const note = document.getElementById('gitlab-validation-note'); + + commentBox.value = ''; + note.innerText = ''; + resetCommentBox(); +} + +function setInProgressState() { + const commentButton = document.getElementById('gitlab-comment-button'); + const commentBox = document.getElementById('gitlab-comment'); + + commentButton.innerText = 'Sending feedback'; + commentButton.classList.replace('gitlab-button-success', 'gitlab-button-secondary'); + commentButton.style.opacity = 0.5; + commentBox.style.color = 'rgba(223, 223, 223, 0.5)'; + commentBox.style.pointerEvents = 'none'; +} + +function storeToken(token) { + const { localStorage } = window; + + // All the browsers we support have localStorage, so let's silently fail + // and go on with the rest of the functionality. + try { + localStorage.setItem('token', token); + } catch (err) { + return; + } +} + +function toggleForm () { + const container = document.getElementById('gitlab-review-container'); + const collapseButton = document.getElementById('gitlab-collapse'); + const form = document.getElementById('gitlab-form-wrapper'); + const OPEN = 'open'; + const CLOSED = 'closed'; + + const stateVals = { + [OPEN]: { + buttonClasses: ['gitlab-collapse-closed', 'gitlab-collapse-open'], + containerClasses: ['gitlab-closed-wrapper', 'gitlab-open-wrapper'], + icon: compressIcon, + display: 'flex', + backgroundColor: 'rgba(255, 255, 255, 1)', + }, + [CLOSED]: { + buttonClasses: ['gitlab-collapse-open', 'gitlab-collapse-closed'], + containerClasses: ['gitlab-open-wrapper', 'gitlab-closed-wrapper'], + icon: commentIcon, + display: 'none', + backgroundColor: 'rgba(255, 255, 255, 0)', + }, + } + +<<<<<<< HEAD:public/visual-review-toolbar.js + const nextState = collapseButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN; + + container.classList.replace(...stateVals[nextState].containerClasses); + container.style.backgroundColor = stateVals[nextState].backgroundColor; + form.style.display = stateVals[nextState].display; + collapseButton.classList.replace(...stateVals[nextState].buttonClasses); + collapseButton.innerHTML = stateVals[nextState].icon; +======= + localStorage.setItem('token', token); +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js +} + +/////////////////////////////////////////////// +///////////////// INJECTION ////////////////// +/////////////////////////////////////////////// + +function noop() {}; + +const eventLookup = ({target: { id }}) => { + switch (id) { + case 'gitlab-collapse': + return toggleForm; + case 'gitlab-comment-button': + const projectDetails = getProjectDetails(); + return postComment.bind(null, projectDetails); + case 'gitlab-login': + return authorizeUser; + case 'gitlab-logout-button': + return logoutUser; + default: + return noop; + } +}; + +window.addEventListener('load', () => { + const content = getInitialState(); + const container = document.createElement('div'); + + container.setAttribute('id', 'gitlab-review-container'); + container.insertAdjacentHTML('beforeend', collapseButton); + container.insertAdjacentHTML('beforeend', form(content)); + + document.body.insertBefore(container, document.body.firstChild); + addStylesheet(); + + document.getElementById('gitlab-review-container').addEventListener('click', (event) => { + eventLookup(event)(); + }); +}); diff --git a/config/karma.config.js b/config/karma.config.js index 2a5bf3581e0..72807798ba2 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -3,7 +3,7 @@ const glob = require('glob'); const chalk = require('chalk'); const webpack = require('webpack'); const argumentsParser = require('commander'); -const webpackConfig = require('./webpack.config.js'); +const webpackConfig = require('./webpack.config.js')[0]; const IS_EE = require('./helpers/is_ee_env'); const ROOT_PATH = path.resolve(__dirname, '..'); diff --git a/config/webpack.config.js b/config/webpack.config.js index 19b48845305..821e4e5b735 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -102,15 +102,32 @@ if (IS_EE) { }); } -module.exports = { +const baseConfig = { mode: IS_PRODUCTION ? 'production' : 'development', context: path.join(ROOT_PATH, 'app/assets/javascripts'), + output: { + path: path.join(ROOT_PATH, 'public/assets/webpack'), + }, + + plugins: [ + // compression can require a lot of compute time and is disabled in CI + new CompressionPlugin(), + ].filter(Boolean), + + devtool: NO_SOURCEMAPS ? false : devtool, +}; + +const mainConfig = { + ...baseConfig, + + name: 'main', + entry: generateEntries, output: { - path: path.join(ROOT_PATH, 'public/assets/webpack'), + ...baseConfig.output, publicPath: '/assets/webpack/', filename: IS_PRODUCTION ? '[name].[chunkhash:8].bundle.js' : '[name].bundle.js', chunkFilename: IS_PRODUCTION ? '[name].[chunkhash:8].chunk.js' : '[name].chunk.js', @@ -236,6 +253,7 @@ module.exports = { }, plugins: [ + ...baseConfig.plugins, // manifest filename must match config.webpack.manifest_filename // webpack-rails only needs assetsByChunkName to function properly new StatsWriterPlugin({ @@ -268,7 +286,7 @@ module.exports = { }), new webpack.NormalModuleReplacementPlugin(/^ee_component\/(.*)\.vue/, function(resource) { - if (Object.keys(module.exports.resolve.alias).indexOf('ee') >= 0) { + if (Object.keys(module.exports[0].resolve.alias).indexOf('ee') >= 0) { resource.request = resource.request.replace(/^ee_component/, 'ee'); } else { resource.request = path.join( @@ -278,9 +296,6 @@ module.exports = { } }), - // compression can require a lot of compute time and is disabled in CI - IS_PRODUCTION && !NO_COMPRESSION && new CompressionPlugin(), - // WatchForChangesPlugin // TODO: publish this as a separate plugin IS_DEV_SERVER && { @@ -339,8 +354,37 @@ module.exports = { inline: DEV_SERVER_LIVERELOAD, }, - devtool: NO_SOURCEMAPS ? false : devtool, - // sqljs requires fs node: { fs: 'empty' }, }; + +const visualReviewToolbarConfig = { + ...baseConfig, + + name: 'visual_review_toolbar', + + entry: './visual_review_toolbar', + + output: { + ...baseConfig.output, + filename: 'visual_review_toolbar.js', + library: 'VisualReviewToolbar', + libraryTarget: 'var', + }, + + module: { + rules: [ + { + test: /\.js$/, + loader: 'babel-loader', + options: { + cacheDirectory: path.join(CACHE_PATH, 'babel-loader'), + }, + }, + ], + }, + + plugins: [...baseConfig.plugins], +}; + +module.exports = [mainConfig, visualReviewToolbarConfig]; diff --git a/public/visual-review-toolbar.js b/public/visual-review-toolbar.js index 6a0fdb29cc2..0a9e497c3cf 100644 --- a/public/visual-review-toolbar.js +++ b/public/visual-review-toolbar.js @@ -105,7 +105,7 @@ const linkStyles = ` background-image: none; `; -const messageStyles = ` +const messageStyles = ` padding: .25rem 0; margin: 0; line-height: 1.2rem; @@ -281,8 +281,13 @@ const comment = ` `; const commentIcon = ` +<<<<<<< HEAD:public/visual-review-toolbar.js icn/comment ` +======= + icn/comment +`; +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js const compressIcon = ` icn/compress @@ -292,8 +297,7 @@ const collapseButton = ` `; - -const form = (content) => ` +const form = content => `
${content}
@@ -319,25 +323,94 @@ const login = ` /////////////////////////////////////////////// // from https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator -function getBrowserId (sUsrAg) { - var aKeys = ["MSIE", "Edge", "Firefox", "Safari", "Chrome", "Opera"], - nIdx = aKeys.length - 1; +function getBrowserId(sUsrAg) { + var aKeys = ['MSIE', 'Edge', 'Firefox', 'Safari', 'Chrome', 'Opera'], + nIdx = aKeys.length - 1; for (nIdx; nIdx > -1 && sUsrAg.indexOf(aKeys[nIdx]) === -1; nIdx--); return aKeys[nIdx]; } +<<<<<<< HEAD:public/visual-review-toolbar.js function addCommentForm () { const formWrapper = document.getElementById('gitlab-form-wrapper'); formWrapper.innerHTML = comment; +======= +function addCommentButtonEvent() { + // get user agent data + const { + innerWidth, + innerHeight, + location: { href }, + navigator: { platform, userAgent }, + } = window; + const browser = getBrowserId(userAgent); + + const scriptName = 'ReviewAppToolbar'; + const projectId = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-project'); + const discussionId = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-discussion'); + const mrUrl = document + .querySelector(`script[data-name='${scriptName}']`) + .getAttribute('data-mr-url'); + const commentButton = document.getElementById('gitlab-comment-button'); + + const details = { + href, + platform, + browser, + userAgent, + innerWidth, + innerHeight, + projectId, + discussionId, + mrUrl, + }; + + commentButton.onclick = postComment.bind(null, details); +} + +function addCollapseEvent() { + const collapseButton = document.getElementById('gitlab-collapse'); + collapseButton.onclick = collapseForm; +} + +function addCommentForm() { + const formWrapper = document.getElementById('gitlab-form-wrapper'); + formWrapper.innerHTML = comment; + removeButtonAndClickEvent('gitlab-login', authorizeUser); + addCommentButtonEvent(); + addLogoutButtonEvent(); +} + +function addLoginButtonEvent() { + const loginButton = document.getElementById('gitlab-login'); + if (loginButton) { + loginButton.onclick = authorizeUser; + } +} + +function addLogoutButtonEvent() { + const logoutButton = document.getElementById('gitlab-logout-button'); + if (logoutButton) { + logoutButton.onclick = logoutUser; + } +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js } -function addLoginForm () { +function addLoginForm() { const formWrapper = document.getElementById('gitlab-form-wrapper'); formWrapper.innerHTML = login; } +<<<<<<< HEAD:public/visual-review-toolbar.js function authorizeUser () { +======= +function authorizeUser() { +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js // Clear any old errors clearNote('gitlab-token'); @@ -357,13 +430,12 @@ function authorizeUser () { return; } -function authSuccess (token) { +function authSuccess(token) { data.token = token; addCommentForm(); } - -function clearNote (inputId) { +function clearNote(inputId) { const note = document.getElementById('gitlab-validation-note'); note.innerText = ''; note.style.color = ''; @@ -374,7 +446,11 @@ function clearNote (inputId) { } } +<<<<<<< HEAD:public/visual-review-toolbar.js function confirmAndClear (mergeRequestId) { +======= +function confirmAndClear(discussionId) { +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js const commentButton = document.getElementById('gitlab-comment-button'); const note = document.getElementById('gitlab-validation-note'); @@ -384,6 +460,7 @@ function confirmAndClear (mergeRequestId) { setTimeout(resetCommentButton, 1000); } +<<<<<<< HEAD:public/visual-review-toolbar.js function getInitialState () { const { localStorage } = window; @@ -410,11 +487,51 @@ function getProjectDetails () { platform, userAgent } } = window; const browser = getBrowserId(userAgent); +======= +function collapseForm() { + const container = document.getElementById('gitlab-review-container'); + const collapseButton = document.getElementById('gitlab-collapse'); + const form = document.getElementById('gitlab-form-wrapper'); + + container.classList.replace('gitlab-open-wrapper', 'gitlab-closed-wrapper'); + container.style.backgroundColor = 'rgba(255, 255, 255, 0)'; + form.style.display = 'none'; + + collapseButton.classList.replace('gitlab-collapse-open', 'gitlab-collapse-closed'); + collapseButton.innerHTML = commentIcon; + collapseButton.onclick = expandForm; +} + +function expandForm() { + const container = document.getElementById('gitlab-review-container'); + const collapseButton = document.getElementById('gitlab-collapse'); + const form = document.getElementById('gitlab-form-wrapper'); + + container.classList.replace('gitlab-closed-wrapper', 'gitlab-open-wrapper'); + container.style.backgroundColor = 'rgba(255, 255, 255, 1)'; + form.style.display = 'flex'; + + collapseButton.classList.replace('gitlab-collapse-closed', 'gitlab-collapse-open'); + collapseButton.innerHTML = compressIcon; + collapseButton.onclick = collapseForm; +} + +function getInitialState() { + const { localStorage } = window; + + if (!localStorage || !localStorage.getItem('token')) { + return { + content: login, + addEvent: addLoginButtonEvent, + }; + } +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js const scriptEl = document.getElementById('review-app-toolbar-script') const { projectId, mergeRequestId, mrUrl } = scriptEl.dataset; return { +<<<<<<< HEAD:public/visual-review-toolbar.js href, platform, browser, @@ -424,10 +541,17 @@ function getProjectDetails () { projectId, mergeRequestId, mrUrl, +======= + content: comment, + addEvent: () => { + addCommentButtonEvent(); + addLogoutButtonEvent(); + }, +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js }; } -function logoutUser () { +function logoutUser() { const { localStorage } = window; // All the browsers we support have localStorage, so let's silently fail @@ -441,7 +565,7 @@ function logoutUser () { addLoginForm(); } -function postComment ({ +function postComment({ href, platform, browser, @@ -466,6 +590,7 @@ function postComment ({ } const detailText = ` +<<<<<<< HEAD:public/visual-review-toolbar.js \n
Metadata @@ -473,6 +598,14 @@ function postComment ({

User agent: ${userAgent}
+======= +
+ Metadata + Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. +

+ *User agent: ${userAgent}* +
+>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js `; const url = ` @@ -482,13 +615,14 @@ function postComment ({ const body = `${commentText} ${detailText}`; fetch(url, { - method: 'POST', - headers: { + method: 'POST', + headers: { 'PRIVATE-TOKEN': data.token, 'Content-Type': 'application/json', }, body: JSON.stringify({ body }), }) +<<<<<<< HEAD:public/visual-review-toolbar.js .then((response) => { if (response.ok) { confirmAndClear(mergeRequestId); @@ -501,9 +635,26 @@ function postComment ({ postError(`The feedback was not sent successfully. Please try again. Error: ${err.message}`, 'gitlab-comment'); resetCommentBox(); }); +======= + .then(response => { + if (response.ok) { + confirmAndClear(discussionId); + return; + } + + throw new Error(`${response.status}: ${response.statusText}`); + }) + .catch(err => { + postError( + `The feedback was not sent successfully. Please try again. Error: ${err.message}`, + 'gitlab-comment', + ); + resetCommentBox(); + }); +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js } -function postError (message, inputId) { +function postError(message, inputId) { const note = document.getElementById('gitlab-validation-note'); const field = document.getElementById(inputId); field.style.borderColor = '#db3b21'; @@ -511,6 +662,16 @@ function postError (message, inputId) { note.innerText = message; } +<<<<<<< HEAD:public/visual-review-toolbar.js +======= +function removeButtonAndClickEvent(buttonId, eventListener) { + const button = document.getElementById(buttonId); + if (button) { + button.removeEventListener(eventListener); + } +} + +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js function resetCommentBox() { const commentBox = document.getElementById('gitlab-comment'); const commentButton = document.getElementById('gitlab-comment-button'); @@ -543,8 +704,7 @@ function setInProgressState() { commentBox.style.pointerEvents = 'none'; } -function storeToken (token) { - +function storeToken(token) { const { localStorage } = window; // All the browsers we support have localStorage, so let's silently fail @@ -580,6 +740,7 @@ function toggleForm () { }, } +<<<<<<< HEAD:public/visual-review-toolbar.js const nextState = collapseButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN; container.classList.replace(...stateVals[nextState].containerClasses); @@ -587,6 +748,9 @@ function toggleForm () { form.style.display = stateVals[nextState].display; collapseButton.classList.replace(...stateVals[nextState].buttonClasses); collapseButton.innerHTML = stateVals[nextState].icon; +======= + localStorage.setItem('token', token); +>>>>>>> a67608fd8b1... Build visual_review_toolbar with webpack:app/assets/javascripts/visual_review_toolbar/index.js } /////////////////////////////////////////////// -- cgit v1.2.1