src/export.html (530 lines of code) (raw):

<html> <head> <title>GitLab</title> <style type="text/css"> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, Cantarell, 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; box-sizing: border-box; font-size: 14px; position: fixed; overflow: hidden; padding: 0; margin: 0; background-color: white; } #wrapper { width: 100vw; height: 100vh; overflow-y: scroll; -webkit-overflow-scrolling: touch; } #brand { margin: 15px; } #content { position: relative; overflow-x: scroll; margin: 0 15px 65px; } .footer { position: absolute; bottom: 0; width: 100%; padding: 15px; text-align: center; border-top: 1px solid #e5e5e5; background-color: #1aaa55; font-weight: bold; color: white; cursor: pointer; } .img-wrapper { margin: 0 -20px; padding: 0 10px; width: 100%; } #img, #img2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); } .headline { display: flex; align-items: flex-end; justify-content: space-between; } .headline h2, .headline h3 { margin: 0 0 10px; } .headline h3 { color: #919191; } #tabs { border-bottom: 1px solid #e5e5e5; } #tabs span { display: inline-block; padding: 10px; margin-bottom: -1px; cursor: pointer; } .active { font-weight: bold; border-bottom: 2px solid #6666c4; } .list-item { cursor: pointer; padding: 10px; border-bottom: 1px solid #eee; } .list-item:hover { background-color: #eee; } .list-item .title { font-weight: bold; margin-bottom: 5px; } .list-item .tag { font-size: 0.75rem; color: #707070; } </style> </head> <body data-app-region="drag"> <div id="wrapper"> <div id="brand"> <img src="https://about.gitlab.com/images/logos/wm_web.svg" width="150" /> </div> <div id="content"> <div id="step1"> <div class="headline"> <h2 class="left">Review your selection</h2> <h3 id="files" class="right"></h3> </div> <div class="img-wrapper"> <div id="img"> <span style="margin-left: 10px">Loading...</span> </div> </div> </div> <div id="step2" style="display: none"> <div id="headline"> <h2 class="left">Where do you want to upload the designs?</h2> </div> <div id="tabs"> <span id="recommended-tab" onclick="switchTab('recommended')" style="display: none" >Recommended</span > <span id="issues-tab" onclick="switchTab('issues')" class="active">Issues</span> <!--<span id="merge-requests-tab" onclick="switchTab('merge-requests')">Merge Requests</span>--> <span id="todos-tab" onclick="switchTab('todos')">To-Do List</span> </div> <div id="recommended" style="display: none">Loading...</div> <div id="issues">Loading...</div> <div id="merge-requests" style="display: none">Loading...</div> <div id="todos" style="display: none">Loading...</div> </div> <div id="step3" style="display: none"> <a onclick="backToStep2()" style=" color: #1b69b6; font-weight: bold; cursor: pointer; margin-bottom: 15px; display: inline-block; " >&lsaquo; Back to previous step</a > <div class="headline"> <h2 class="left" id="targetTitle"></h2> </div> <div id="details">Loading...</div> </div> </div> <div id="footer1" class="footer" onclick="toStep2()">Looks good, continue!</div> <div id="footer3" class="footer" onclick="uploadDesigns()" style="display: none"> Upload my designs! </div> </div> </body> <script> let todos = new Array(); let issuesPagination; let mergeRequestsPagination; let todosPagination; let target; let key; let name; let filename; /** * START: self-managed GitLab instance configuration. * Edit these values for your instance. Defaults to gitlab.com configuration. */ const GITLAB_INSTANCE_PROTOCOL = 'https'; const GITLAB_INSTANCE_HOST = 'gitlab.com'; /** * END: self-managed GitLab instance configuration. */ const GITLAB_INSTANCE_BASE_URL = `${GITLAB_INSTANCE_PROTOCOL}://${GITLAB_INSTANCE_HOST}`; const GITLAB_API_BASE_URL = `${GITLAB_INSTANCE_BASE_URL}/api/v4`; const GITLAB_GRAPHQL_BASE_URL = `${GITLAB_INSTANCE_BASE_URL}/api/graphql`; function switchTab(context) { cleanTabs(); document.getElementById(context + '-tab').classList.add('active'); document.getElementById(context).style.display = 'block'; } function cleanTabs() { document.getElementById('recommended-tab').classList.remove('active'); document.getElementById('issues-tab').classList.remove('active'); //document.getElementById('merge-requests-tab').classList.remove('active'); document.getElementById('todos-tab').classList.remove('active'); document.getElementById('recommended').style.display = 'none'; document.getElementById('issues').style.display = 'none'; //document.getElementById('merge-requests').style.display = 'none'; document.getElementById('todos').style.display = 'none'; } function toStep2() { document.getElementById('step1').style.display = 'none'; document.getElementById('footer1').style.display = 'none'; document.getElementById('step2').style.display = 'block'; } function backToStep2() { target = {}; document.getElementById('step3').style.display = 'none'; document.getElementById('footer3').style.display = 'none'; document.getElementById('step2').style.display = 'block'; } function toStep3() { document.getElementById('step2').style.display = 'none'; document.getElementById('footer3').style.display = 'block'; document.getElementById('step3').style.display = 'block'; } function uploadDesigns() { document.getElementById('footer3').innerHTML = 'Uploading...'; window.postMessage('submitDesign', target.project.path_with_namespace, target.iid); } function displayItem(result, key, name, context) { let element = document.createElement('div'); let title = document.createElement('div'); let tag = document.createElement('div'); element.classList.add('list-item'); title.classList.add('title'); tag.classList.add('tag'); title.innerHTML = result.title; tag.innerHTML = result.project.name_with_namespace + '#' + result.iid; element.onclick = function () { target = result; document.getElementById('targetTitle').innerHTML = result.title; document.getElementById('details').innerHTML = 'Loading...'; toStep3(); fetch(GITLAB_GRAPHQL_BASE_URL, { headers: { Authorization: 'Bearer ' + key, 'Content-Type': 'application/json', }, body: JSON.stringify({ query: `{ project(fullPath: "${result.project.path_with_namespace}") { issue(iid: "${result.iid}") { designCollection { designs { edges { node { fullPath, filename, image } } } } } } }`, }), method: 'POST', }) .then((response) => { return response.json(); }) .then((result2) => { let string = ''; let imgWrapper = document.createElement('div'); imgWrapper.classList.add('img-wrapper'); let img2 = document.createElement('div'); img2.setAttribute('id', 'img2'); imgWrapper.appendChild(img2); const designs = result2.data.project.issue.designCollection.designs.edges; if (designs.length > 0) { designs.forEach((image) => { let div = document.createElement('div'); let imgContainer = document.createElement('div'); let img = document.createElement('img'); let description = document.createElement('p'); description.innerHTML = image.node.filename; img.setAttribute('id', 'test'); img.src = image.node.image; img.style = 'max-width: 100%; max-height: 100%'; imgContainer.style = 'height:200px; display: flex; align-items: center; justify-content: center'; description.style = 'word-break: break-all;background-color: #eee;margin: 0;padding: 10px;border-top: 1px solid #e5e5e5;text-overflow: ellipsis; white-space: nowrap; overflow: hidden'; div.style = 'margin: 10px;max-width: 250px;border: 1px solid #e5e5e5;border-radius: 0.25rem;'; imgContainer.appendChild(img); div.appendChild(imgContainer); div.appendChild(description); img2.appendChild(div); }); document.getElementById('details').innerHTML = ''; document.getElementById('details').appendChild(imgWrapper); } else { document.getElementById('details').innerHTML = 'No images uploaded yet'; } //document.getElementById('details').innerHTML += '<h3>' + result.title + '</h3><p><img width="40" height="40" style="float:left;border-radius:50%;margin:0 8px" src="' + result.author.avatar_url + '">' + result.description + '</p><textarea id="comment" rows=5 columns="40">![' + name + '](/' + name + '.png)</textarea><br/><button onclick="window.postMessage(\'submitComment\', \'' + result.project_id + '\', \'' + result.iid + '\', document.getElementById(\'comment\').value)">Comment</button><button onclick="window.postMessage(\'submitDesign\', \'' + result.project_id + '\', \'' + result.iid + '\')">Upload to Designs</button><button onclick="window.postMessage(\'openTodo\', \'' + result.web_url + '\')">Open in browser</button>'; }) .catch((error) => { console.error(error); document.getElementById('footer3').style.display = 'none'; document.getElementById('details').innerHTML = 'Can\'t upload images to "' + result.title + '", as it does not have a GitLab Premium or GitLab.com Silver license.'; //document.getElementById('details').innerHTML = '<h3>' + result.title + '</h3><p><img width="40" height="40" style="float:left;border-radius:50%;margin:0 8px" src="' + result.author.avatar_url + '">' + result.description + '</p><textarea id="comment" rows=5 columns="40">![' + name + '](/' + name + '.png)</textarea><br/><button onclick="window.postMessage(\'submitComment\', \'' + result.project_id + '\', \'' + result.iid + '\', document.getElementById(\'comment\').value)">Comment</button><button onclick="window.postMessage(\'submitDesign\', \'' + result.project_id + '\', \'' + result.iid + '\')">Upload to Designs</button><button onclick="window.postMessage(\'openTodo\', \'' + result.web_url + '\')">Open in browser</button>'; }); }; element.appendChild(title); element.append(tag); document.getElementById(context).appendChild(element); } function displayImages() {} function parseLinkHeader(header) { if (header.length === 0) { throw new Error('input must not be of zero length'); } return header.split(/(?!\B"[^"]*),(?![^"]*"\B)/).reduce((links, part) => { const section = part.split(/(?!\B"[^"]*);(?![^"]*"\B)/); if (section.length < 2) { throw new Error("section could not be split on ';'"); } const url = section[0].replace(/<(.*)>/, '$1').trim(); const name1 = section[1].replace(/rel="(.*)"/, '$1').trim(); links[name1] = url; return links; }, {}); } function bufferToBase64(buf) { var binstr = Array.prototype.map .call(buf, function (ch) { return String.fromCharCode(ch); }) .join(''); return btoa(binstr); } window.postMessage('needKey', 'test'); window.getImage = function (images) { document.getElementById('img').innerHTML = ''; images.forEach((arg) => { let div = document.createElement('div'); let imgContainer = document.createElement('div'); let img = document.createElement('img'); let description = document.createElement('p'); description.innerHTML = arg.name + '.png'; img.setAttribute('id', 'test'); img.src = 'data:image/jpeg;base64,' + bufferToBase64(arg.image.data); img.style = 'max-width: 100%; max-height: 100%'; imgContainer.style = 'height:200px; display: flex; align-items: center; justify-content: center'; description.style = 'word-break: break-all;background-color: #eee;margin: 0;padding: 10px;border-top: 1px solid #e5e5e5;text-overflow: ellipsis; white-space: nowrap; overflow: hidden'; div.style = 'margin: 10px;max-width: 250px;border: 1px solid #e5e5e5;border-radius: 0.25rem;'; imgContainer.appendChild(img); div.appendChild(imgContainer); div.appendChild(description); if (images.length == 1) { document.getElementById('files').innerHTML = '1 file'; } else { document.getElementById('files').innerHTML = images.length + ' files'; } document.getElementById('img').appendChild(div); }); }; window.getKey = function (key, name, filename, userId) { if (filename.indexOf('#') != -1) { let filenameArray = filename.split('#'); let projecthandle = filenameArray[0]; let issue = filenameArray[1].split('-')[0]; let projectId; if (projecthandle == 'ce') { projectId = 13083; } else if (projecthandle == 'ee') { projectId = 278964; } else { projectId = encodeURIComponent(projecthandle.replace(':', '/')); } fetch( `${GITLAB_API_BASE_URL}/projects/` + projectId + '/issues/' + issue + 'access_token=' + key, {}, ) .then(function (response) { if (!response.ok) { throw Error(response.status); } return response; }) .then((response) => { return response.json(); }) .then((result) => { fetch( `${GITLAB_API_BASE_URL}/projects/` + result.project_id + '?access_token=' + key, {}, ) .then(function (response) { if (!response.ok) { throw Error(response.status); } return response; }) .then((response) => { return response.json(); }) .then((success2) => { result.project = { name_with_namespace: success2.name_with_namespace, path_with_namespace: success2.path_with_namespace, }; document.getElementById('recommended').innerHTML = ''; displayItem(result, key, name, 'recommended'); document.getElementById('recommended-tab').style.display = 'inline-block'; switchTab('recommended'); }); }); } fetch(`${GITLAB_API_BASE_URL}/todos?access_token=` + key, {}) .then(function (response) { if (!response.ok) { throw Error(response.status); } todosPagination = parseLinkHeader(response.headers.get('Link')); return response; }) .then((response) => { return response.json(); }) .then((success) => { let string = document.createElement('div'); document.getElementById('todos').innerHTML = ''; success.forEach((result) => { result.title = result.target.title; result.project_id = result.target.project_id; result.description = result.body; result.iid = result.target.iid; todos[result.id] = result; result.web_url = result.target_url; if (result.target_type == 'Issue') { displayItem(result, key, name, 'todos'); } if (todosPagination.next) { //build pagination } }); }) .catch((error) => { window.postMessage('newKey', error.message); console.log(error); }); fetch( `${GITLAB_API_BASE_URL}/issues?assignee_id=` + userId + '&state=opened&scope=all&order_by=updated_at&sort=desc&per_page=100&access_token=' + key, {}, ) .then(function (response) { if (!response.ok) { throw Error(response.status); } issuesPagination = parseLinkHeader(response.headers.get('Link')); return response; }) .then((response) => { return response.json(); }) .then(async (success) => { document.getElementById('issues').innerHTML = ''; for (result of success) { result.project = { name_with_namespace: result.references.full.replace('#' + result.iid, ''), path_with_namespace: result.references.full.replace('#' + result.iid, ''), }; todos[result.id] = result; displayItem(result, key, name, 'issues'); } }) .catch((error) => { window.postMessage('newKey', error.message); console.log(error); }); fetch( `${GITLAB_API_BASE_URL}/merge_requests?assignee_id=` + userId + '&state=opened&scope=all&per_page=10&access_token=' + key, {}, ) .then(function (response) { if (!response.ok) { throw Error(response.status); } mergeRequestsPagination = parseLinkHeader(response.headers.get('Link')); return response; }) .then((response) => { return response.json(); }) .then((success) => { let string = document.createElement('div'); success.forEach((result) => { document.getElementById('merge-requests').innerHTML = ''; fetch( `${GITLAB_API_BASE_URL}/projects/` + result.project_id + '?access_token=' + key, {}, ) .then(function (response) { if (!response.ok) { throw Error(response.status); } return response; }) .then((response) => { return response.json(); }) .then((success2) => { result.project = { name_with_namespace: success2.name_with_namespace, path_with_namespace: success2.path_with_namespace, }; todos[result.id] = result; displayItem(result, key, name, 'merge-requests'); if (mergeRequestsPagination.next) { //build pagination } }); }); }) .catch((error) => { window.postMessage('newKey', error.message); console.log(error); }); }; </script> </html>