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;
"
>‹ 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"></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"></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>