diff options
Diffstat (limited to 'public/visual-review-toolbar.js')
-rw-r--r-- | public/visual-review-toolbar.js | 628 |
1 files changed, 0 insertions, 628 deletions
diff --git a/public/visual-review-toolbar.js b/public/visual-review-toolbar.js deleted file mode 100644 index 6a0fdb29cc2..00000000000 --- a/public/visual-review-toolbar.js +++ /dev/null @@ -1,628 +0,0 @@ -/////////////////////////////////////////////// -/////////////////// 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 = ` - <p id='gitlab-validation-note' class='gitlab-message'></p> -`; - -const comment = ` - <div> - <textarea id='gitlab-comment' name='gitlab-comment' rows='3' placeholder='Enter your feedback or idea' class='gitlab-input'></textarea> - ${note} - <p class='gitlab-metadata-note'>Additional metadata will be included: browser, OS, current page, user agent, and viewport dimensions.</p> - </div> - <div class='gitlab-button-wrapper''> - <button class='gitlab-button-secondary' style='${buttonClearStyles}' type='button' id='gitlab-logout-button'> Logout </button> - <button class='gitlab-button-success' style='${buttonClearStyles}' type='button' id='gitlab-comment-button'> Send feedback </button> - </div> -`; - -const commentIcon = ` - <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/comment</title><path d="M4 11.132l1.446-.964A1 1 0 0 1 6 10h5a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v6.132zM6.303 12l-2.748 1.832A1 1 0 0 1 2 13V5a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v4a3 3 0 0 1-3 3H6.303z" id="gitlab-comment-icon"/></svg> -` - -const compressIcon = ` - <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/compress</title><path d="M5.27 12.182l-1.562 1.561a1 1 0 0 1-1.414 0h-.001a1 1 0 0 1 0-1.415l1.56-1.56L2.44 9.353a.5.5 0 0 1 .353-.854H7.09a.5.5 0 0 1 .5.5v4.294a.5.5 0 0 1-.853.353l-1.467-1.465zm6.911-6.914l1.464 1.464a.5.5 0 0 1-.353.854H8.999a.5.5 0 0 1-.5-.5V2.793a.5.5 0 0 1 .854-.354l1.414 1.415 1.56-1.561a1 1 0 1 1 1.415 1.414l-1.561 1.56z" id="gitlab-compress-icon"/></svg> -`; - -const collapseButton = ` - <button id='gitlab-collapse' style='${buttonClearStyles}' class='gitlab-collapse-open gitlab-button-secondary'>${compressIcon}</button> -`; - - -const form = (content) => ` - <div id='gitlab-form-wrapper'> - ${content} - </div> -`; - -const login = ` - <div> - <label for='gitlab-token' class='gitlab-label'>Enter your <a class='gitlab-link' href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">personal access token</a></label> - <input class='gitlab-input' type='password' id='gitlab-token' name='gitlab-token'> - ${note} - </div> - <div class='gitlab-checkbox-wrapper'> - <input type="checkbox" id="remember_token" name="remember_token" value="remember"> - <label for="remember_token" class='gitlab-checkbox-label'>Remember me</label> - </div> - <div class='gitlab-button-wrapper'> - <button class='gitlab-button-wide gitlab-button-success' style='${buttonClearStyles}' type='button' id='gitlab-login'> Submit </button> - </div> -`; - -/////////////////////////////////////////////// -//////////////// 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]; -} - -function addCommentForm () { - const formWrapper = document.getElementById('gitlab-form-wrapper'); - formWrapper.innerHTML = comment; -} - -function addLoginForm () { - const formWrapper = document.getElementById('gitlab-form-wrapper'); - formWrapper.innerHTML = login; -} - -function authorizeUser () { - // 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 = ''; - } -} - -function confirmAndClear (mergeRequestId) { - 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); -} - -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); - - const scriptEl = document.getElementById('review-app-toolbar-script') - const { projectId, mergeRequestId, mrUrl } = scriptEl.dataset; - - return { - href, - platform, - browser, - userAgent, - innerWidth, - innerHeight, - projectId, - mergeRequestId, - mrUrl, - }; -} - -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 = ` - \n -<details> - <summary>Metadata</summary> - Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. - <br /><br /> - <em>User agent: ${userAgent}</em> -</details> - `; - - 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 }), - }) - .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(); - }); -} - -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; -} - -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)', - }, - } - - 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; -} - -/////////////////////////////////////////////// -///////////////// 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)(); - }); -}); |