Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,59 @@ body {

textarea {
margin-bottom: 10px;
}

#auto-generation {
border-radius: 15px;
padding: 20px;
padding-bottom: 25px;
margin-top: 20px;
margin-bottom: 20px;
background: lightgray;
width: 100%;
max-width: 800px;
box-sizing: border-box;
}

#github-url-form {
margin-top: 25px;
width: 100%;
}

#repo-url {
width: 100%;
max-width: 750px;
box-sizing: border-box;
}

#repo-url-button {
margin-top: 10px;
border-radius: 5px;
}

#notification {
padding: 10px;
margin-bottom: 15px;
border-radius: 5px;
position: relative;
width: 100%;
max-width: 800px;
box-sizing: border-box;
animation: slideDown 0.3s ease;
}

#notification-message {
margin: 0;
padding-right: 20px;
}

@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
19 changes: 19 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<html>
<head>
<meta charset="utf-8">
Comment thread
sachin-panayil marked this conversation as resolved.
<!-- USWDS not working -->
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> -->
<!-- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> -->
Expand All @@ -24,6 +25,7 @@
<!-- Render the form -->
<script src="js/generateFormComponents.js"></script>
<script src="js/formDataToJson.js"></script>
<script src="js/autoGenerateFields.js"></script>
<script type="text/javascript">
createFormComponents()
.then((components) => {
Expand All @@ -38,6 +40,7 @@
},
components: components,
}).then(function (form) {
window.formIOInstance = form;
form.on("submit", function (submission) {
console.log("form submission here:", submission);
createCodeJson(submission.data);
Expand All @@ -51,12 +54,28 @@
</head>
<body>
<div id="form-header"></div>

<div id="notification" style="display: none;">
<p id="notification-message"></p>
</div>

<div id="auto-generation">
<p id="auto-generation-header"></p>
<form id="github-url-form">
<label for="repo-url">GitHub Repository URL</label><br>
<input type="text" id="repo-url" name="repo-url"><br>
<input type="submit" id="repo-url-button" value="Submit">
</form>
</div>

<div id="formio"></div>

<div id="output">
<label for="json-result">Your JSON Metadata </label>
<textarea class="form-control" rows="10" id="json-result" readonly></textarea>
<button type="button" class="btn btn-outline" href="#" onclick="copyToClipboard(event)">Copy</button>
<button type="button" class="btn btn-outline" href="#" onclick="downloadFile(event)">Download</button>
</div>

</body>
</html>
215 changes: 215 additions & 0 deletions js/autoGenerateFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// We wait for DOM to be fully loaded before initializing
document.addEventListener("DOMContentLoaded", function() {
setupFormHandler();
setupNotificationSystem();
});

// This works by creating an object with methods for different notification types of either error or success
// Calling either of these methods calls the main functionality, show(), which manipulates the notification element in HTML
// The show() method changes the element based on type and displays the message to the user
// The hide() function makes sure that the notification fades away after 5 seconds
const notificationSystem = {
Comment thread
sachin-panayil marked this conversation as resolved.
show: function(message, type = 'error') {
const notification = document.getElementById('notification');
const messageElement = document.getElementById('notification-message');

messageElement.textContent = message;

if (type === 'error') {
notification.style.backgroundColor = '#f8d7da';
notification.style.color = '#721c24';
notification.style.border = '1px solid #f5c6cb';
} else {
notification.style.backgroundColor = '#d4edda';
notification.style.color = '#155724';
notification.style.border = '1px solid #c3e6cb';
}

notification.style.display = 'block';
setTimeout(() => {
notification.style.opacity = '1';
}, 10);

clearTimeout(this.timeout);
this.timeout = setTimeout(() => this.hide(), 5000);
},

hide: function() {
const notification = document.getElementById('notification');
notification.style.opacity = '0';
setTimeout(() => {
notification.style.display = 'none';
}, 500);
},

error: function(message) {
this.show(message, 'error');
},

success: function(message) {
this.show(message, 'success');
},
};

function setupNotificationSystem() {
const notification = document.getElementById('notification');
if (notification) {
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.5s ease';
}
}

function setupFormHandler() {
const form = document.getElementById("github-url-form");

form.addEventListener("submit", async function(event) {
event.preventDefault();

const submitButton = document.getElementById("repo-url-button");

submitButton.value = "Loading...";
submitButton.disabled = true;

try {
const repoURL = document.getElementById("repo-url").value;

if (repoURL.length == 0) {
throw new Error("Please enter a GitHub repository URL");
}

const repoInfo = extractGitHubInfo(repoURL);

if (!repoInfo) {
Comment thread
sachin-panayil marked this conversation as resolved.
throw new Error("Invalid GitHub URL format. Please enter a valid GitHub repository URL ->(https://github.com/username/repository)");
}

const repositoryInfo = await getRepoInformation(repoInfo);
const languages = await getRepoLanguages(repoInfo)

if (repositoryInfo) {
preFillFields(repositoryInfo, languages);
notificationSystem.success("Repository data loaded successfully!");
} else {
throw new Error("Could not fetch repository information. Please check the URL and try again.");
}

} catch (error) {
console.error(error.message);
notificationSystem.error(error.message);
} finally {
submitButton.value = "Submit";
submitButton.disabled = false;
}
});
}

function extractGitHubInfo(url) {
// Regex pattern to match GitHub URLs and extract org and repo
const regex = /(?:https?:\/\/)?(?:www\.)?github\.com\/([^\/]+)\/([^\/\s]+)/;
const match = url.match(regex);

if (match && match.length === 3) {
return {
organization: match[1],
repository: match[2]
};
}

return null;
}

async function getRepoInformation(repoInfo) {
const baseURL = "https://api.github.com/repos/";
const endpoint = `${baseURL}${repoInfo.organization}/${repoInfo.repository}`;

try {
const response = await fetch(endpoint);

if (!response.ok) {
throw new Error(`GitHub API error (${response.status}): ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error("Fetch error:", error.message);
}
}

async function getRepoLanguages(repoInfo) {
const endpoint = `https://api.github.com/repos/${repoInfo.organization}/${repoInfo.repository}/languages`

try {
const response = await fetch(endpoint);

if (!response.ok) {
throw new Error(`GitHub API error (${response.status}): ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error("Fetch error:", error.message);
}
}

function preFillFields(repoData, languages) {
if (!window.formIOInstance) {
notificationSystem.error("Form interface not initialized. Please refresh and try again.");
return;
}

try {
let licenses = [];
if (repoData.license && repoData.license.spdx_id) {
licenses.push({
name: repoData.license.spdx_id,
URL: repoData.html_url + "/blob/main/LICENSE"
});
}

const submission = {
data: {
name: repoData.name || '',
description: repoData.description || '',

repositoryURL: repoData.html_url || '',
repositoryVisibility: repoData.private ? "private" : "public",
Comment thread
sachin-panayil marked this conversation as resolved.
vcs: 'git',

Comment thread
sachin-panayil marked this conversation as resolved.
permissions: {
licenses: licenses
},

reuseFrequency: {
forks: repoData.forks_count || 0
},

languages: Object.keys(languages) || [],

date: {
created: repoData.created_at || '',
lastModified: repoData.updated_at || '',
metaDataLastUpdated: new Date().toISOString()
},

tags: repoData.topics || [],

feedbackMechanisms: [repoData.html_url + "/issues"]
}
};

window.formIOInstance.setSubmission(submission);

} catch (error) {
notificationSystem.error("Error filling form fields with repository data. Please refresh and try again");
console.error("Form fill error:", error);
}
}

// This is global so we could use this throughout the website!
window.showErrorNotification = function(message) {
notificationSystem.error(message);
};

window.showSuccessNotification = function(message) {
notificationSystem.success(message);
};
6 changes: 6 additions & 0 deletions js/generateFormComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ function createFormHeading(title, description) {
container.innerHTML = `<h1>${title}</h1>\n<h2>${description}</h2>`;
}

function createAutoGenerationBox() {
const container = document.getElementById("auto-generation-header")
container.innerHTML = `<h3>Auto Generate Fields</h3> \n <h4> Please enter your repositories GitHub URL in order to automatically pre-fill some of the fields in this form! </h4> \n <h6> <i>This currently only works on <b>public</b> repositories</i> </h6>`
}

// Iterates through each json field and creates component array for Form.io
function createAllComponents(schema, prefix = ""){
let components = [];
Expand Down Expand Up @@ -293,6 +298,7 @@ async function createFormComponents() {
console.log("JSON Data:", jsonData);

createFormHeading(jsonData["title"], jsonData["description"]);
createAutoGenerationBox()

components = createAllComponents(jsonData);

Expand Down
Loading