diff options
Diffstat (limited to 'src')
27 files changed, 0 insertions, 2340 deletions
diff --git a/src/api/git.js b/src/api/git.js deleted file mode 100644 index 95759f0..0000000 --- a/src/api/git.js +++ /dev/null @@ -1,415 +0,0 @@ -const { formatDistance } = require('date-fns'); -const fs = require('fs'); -const git = require("nodegit"); -const zlib = require("zlib"); -const { spawn } = require('child_process'); -const whatwg = require("whatwg-url"); -const path = require("path"); - -function addRepoDirSuffix(repo_name) -{ -	if(!repo_name.endsWith(".git")) { -		return repo_name + ".git"; -	} -	return repo_name; -} - -async function getLog(base_dir, repo_name) -{ -	const repo = await git.Repository.openBare(`${base_dir}/${repo_name}`); - -	const walker = git.Revwalk.create(repo); -	walker.pushHead(); - -	const raw_commits = await walker.getCommitsUntil(() => true); -	 -	const commits = Promise.all(raw_commits.map(async commit => ({ -		commit: commit.sha(), -		author_full: commit.author().toString(), -		author_name: commit.author().name(), -		author_email: commit.author().email(), -		date: commit.date(), -		message: commit.message().replace(/\n/g, ""), -		insertions: (await (await commit.getDiff())[0].getStats()).insertions(), -		deletions: (await (await commit.getDiff())[0].getStats()).deletions(), -		files_changed: (await (await commit.getDiff())[0].getStats()).filesChanged() -	})));		 - -	return await commits; -} - -async function getTimeSinceLatestCommit(base_dir, repo_name) -{ -	const repo = await git.Repository.openBare(`${base_dir}/${repo_name}`); -	const master_commit = await repo.getMasterCommit(); - -	return formatDistance(new Date(), master_commit.date()); -} - -function getRepoFile(base_dir, repo, file) -{ -	return new Promise(resolve => -	{ -		fs.readFile(`${base_dir}/${repo}/${file}`, async (err, content) => -		{			 -			if(!err) { -				resolve(content.toString().replace(/\n/g, "")); -				return; -			} -			resolve(""); -		}); -	}); -} - -function getRepos(base_dir) -{ -	return new Promise((resolve) => -	{ -		fs.readdir(base_dir, (err, dir_content) => -		{ -			if(err) { -				resolve({ "error": err }); -				return; -			} -			 -			dir_content.filter(repo => repo.endsWith(".git")).reduce((acc, repo) => -			{ -				return acc.then((repos) => -				{ -					return getRepoFile(base_dir, repo, "description").then((description) => -					{ -						return getRepoFile(base_dir, repo, "owner").then((owner) => -						{ -							return getTimeSinceLatestCommit(base_dir, repo).then((last_commit_date) => -							{ -								repos[repo.slice(0, -4)] = { "description": description, "owner": owner, "last_updated": last_commit_date }; -								return repos; -							}); -						}); -					}); -				}); -			}, Promise.resolve({})).then((repos) => -			{ -				resolve(repos); -			}); -		}); -	}); -} - -function parseHunkAddDel(hunk) -{ -	let new_lines = []; -	let deleted_lines = []; - -	hunk.forEach((line, index) => -	{ -		if(line.charAt(0) === '+') { -			hunk[index] = line.slice(1); -			new_lines.push(index); -		} -		else if(line.charAt(0) === '-') { -			hunk[index] = line.slice(1); -			deleted_lines.push(index); -		} -	}); - -	return { new: new_lines, deleted: deleted_lines, hunk: hunk.join("\n") }; -} - -async function getCommit(base_dir, repo_name, commit_oid) -{ -	repo_name = addRepoDirSuffix(repo_name); - -	const repo = await git.Repository.openBare(`${base_dir}/${repo_name}`); -	const commit = await repo.getCommit(commit_oid); -	const diff = (await commit.getDiff())[0]; -	const all_patches = (await diff.toBuf(1)).split('\n'); - -	// Get the count of lines for all of patches's headers -	const patch_headers = (await diff.toBuf(2)).split('\n'); -	const patch_header_data = await patch_headers.reduce((acc, line, index) => -	{ -		return acc.then((arr) => -		{ -			if(/^diff --git/.test(line)) { -				arr[0].push(all_patches.indexOf(line)); -				 -				if(arr[2] != undefined) { -					arr[1].push(patch_headers.slice(arr[2], index).length); -				} -				arr[2] = index; -			} -			else if(index == patch_headers.length - 1 && arr[2] != undefined) { -				arr[1].push(patch_headers.slice(arr[2], index).length); -			} -			return arr; -		}); -	}, Promise.resolve([ [], [], undefined ])); -	 -	console.log(patch_header_data); - -	const patches = await diff.patches(); -	const parsed_patches = patches.reduce((acc, patch, patch_index) => -	{ -		return acc.then((arr) => -		{ -			return patch.hunks().then((hunks) => -			{ -				console.log("\n" + patch.newFile().path()); -				 -				const patch_start = patch_header_data[0][patch_index] + patch_header_data[1][patch_index]; -				const patch_end = (patch_header_data[0][patch_index + 1] !== undefined) ? patch_header_data[0][patch_index + 1] : all_patches.length - 1; -				const patch_content = all_patches.slice(patch_start, patch_end); - -				const line_lengths = patch_content.map((line) => line.length).reduce((acc, length) => acc + length); -				 -				if(patch_content.length > 5000 || line_lengths > 5000) { -					console.log("Too large!"); -					 -					arr.push({ -						from: patch.oldFile().path(), -						to: patch.newFile().path(), -						additions: patch.lineStats()["total_additions"], -						deletions: patch.lineStats()["total_deletions"], -						too_large: true, -						hunks: null -					}); -					return arr; -				} - -				// Go through all of the patch's hunks -				// Patches are split into parts of where in the file the change is made. Those parts are called hunks. -				return hunks.reduce((acc, hunk, hunk_index) => -				{ -					return acc.then((hunks_data) => -					{ -						const hunk_header = hunk.header(); -						const hunk_header_index = patch_content.indexOf(hunk_header.replace(/\n/g, "")); - -						if(hunks_data[0] !== undefined) { -							const prev_hunk = hunks[hunk_index - 1]; -							hunks_data[1].push(Object.assign({ -								new_start: prev_hunk.newStart(), -								new_lines: prev_hunk.newLines(), -								old_start: prev_hunk.oldStart(), -								old_lines: prev_hunk.oldLines() -							}, parseHunkAddDel(patch_content.slice(hunks_data[0], hunk_header_index)))); - -							hunks_data[2] = hunks_data + patch_content.slice(hunks_data[0], hunk_header_index).length; -						} - -						hunks_data[0] = hunk_header_index; -						return hunks_data; -					}); -				}, Promise.resolve([ undefined, [], 0 ])).then((hunks_data) => -				{ -					const prev_hunk = hunks[hunks.length - 1]; -					hunks_data[1].push(Object.assign({ -						new_start: prev_hunk.newStart(), -						new_lines: prev_hunk.newLines(), -						old_start: prev_hunk.oldStart(), -						old_lines: prev_hunk.oldLines() -					}, parseHunkAddDel(patch_content.slice(hunks_data[0], patch_end)))); - -					arr.push({ -						from: patch.oldFile().path(), -						to: patch.isDeleted() ? "/dev/null" : patch.newFile().path(), -						additions: patch.lineStats()["total_additions"], -						deletions: patch.lineStats()["total_deletions"], -						too_large: false, -						hunks: hunks_data[1] -					}); - -					return arr; -				}); -			}); -		}); -	}, Promise.resolve([])); - -	return { -		hash: commit.sha(), -		author: commit.author().toString(), -		message: commit.message(), -		date: commit.date(), -		patches: await parsed_patches -	}; -} - -async function doesCommitExist(base_dir, repo_name, commit_oid) -{ -	const repo = await git.Repository.openBare(`${base_dir}/${repo_name}`); - -	try { -		await repo.getCommit(commit_oid); -		return true; -	} -	catch { -		return false; -	} -} - -function connectToGitHTTPBackend(base_dir, req, reply) -{ -	const url_path = req.url.replace(req.params.repo, req.params.repo + ".git"); -	const repo = req.params.repo + ".git"; -	const repo_path = path.join(base_dir, repo); - -	req = req.headers['Content-Encoding'] == 'gzip' ? req.pipe(zlib.createGunzip()) : req; - -	const parsed_url = new whatwg.URL(`${req.protocol}://${req.hostname}${url_path}`); -	const url_path_parts = parsed_url.pathname.split('/'); -	 -	let service; -	let info = false; - -	if(/\/info\/refs$/.test(parsed_url.pathname)) { -		service = parsed_url.searchParams.get("service"); -		info = true; -	} -	else { -		service = url_path_parts[url_path_parts.length-1]; -	} -		 -	const content_type = `application/x-${service}-${info ? "advertisement" : "result"}`; - -	if(/\.\/|\.\./.test(parsed_url.pathname)) { -		reply.header("Content-Type", content_type); -		reply.code(404).send("Git repository not found!\n"); -		return; -	} - -	if(service !== 'git-upload-pack') { -		reply.header("Content-Type", content_type); -		reply.code(403).send("Access denied!\n"); -		return; -	} -		 -	reply.raw.writeHead(200, { "Content-Type": content_type }); - -	const spawn_args = [ "--stateless-rpc", repo_path ]; - -	if(info) { -		spawn_args.push("--advertise-refs"); -	} - -	const git_pack = spawn(service, spawn_args); -	 -	if(info) { -		const s = '# service=' + service + '\n'; -		const n = (4 + s.length).toString(16); -		reply.raw.write(Buffer.from((Array(4 - n.length + 1).join('0') + n + s) + '0000')); -	} -	else { -		req.body.on("data", (data) => git_pack.stdin.write(data)); -		req.body.on("close", () => git_pack.stdin.end()); -	} - -	git_pack.on("error", (err) => console.log(err)); -	git_pack.stderr.on("data", (stderr) => console.log(stderr)); - -	git_pack.stdout.on("data", (data) => -	{ -		reply.raw.write(data); -	}); - -	git_pack.on("close", () => reply.raw.end()); -} - -async function getTree(base_dir, repo_name, tree_path) -{ -	repo_name = addRepoDirSuffix(repo_name); - -	const repo = await git.Repository.openBare(`${base_dir}/${repo_name}`); -	const master_commit = await repo.getMasterCommit(); - -	const tree = await master_commit.getTree(); - -	let entries; -	if(tree_path) { -		try { -			const path_entry = await tree.getEntry(tree_path); - -			if(path_entry.isBlob()) { -				return { type: "blob", content: (await path_entry.getBlob()).content().toString() }; -			} - -			entries = await (await path_entry.getTree()).entries(); -		} -		catch(err) { -			if(err.errno === -3) { -				return { error: 404 }; -			} -			return { error: 500 }; -		} -	} -	else { -		entries = tree.entries(); -	} -	 -	return { type: "tree", tree: await entries.reduce((acc, entry) => -	{ -		return acc.then((obj) => -		{ -			return getTreeEntryLastCommit(repo, entry).then((last_commit) => -			{ -				obj[path.parse(entry.path()).base] = { -					oid: entry.oid(), -					type: entry.isBlob() ? "blob" : "tree", -					last_commit: { -						id: last_commit.id, -						message: last_commit.message, -						time: last_commit.time -					} -				}; -				return obj; -			}); -		}); -	}, Promise.resolve({})) }; -} - -async function getTreeEntryLastCommit(repo, tree_entry) -{ -	const walker = git.Revwalk.create(repo); -	walker.pushHead(); - -	const raw_commits = await walker.getCommitsUntil(() => true); -	 -	return raw_commits.reduce((acc, commit) => -	{ -		return acc.then((obj) => -		{ -			if(Object.keys(obj).length == 0) { -				return commit.getDiff().then((diffs) => -				{ -					return diffs[0].patches().then((patches) => -					{ -						let matching_path_patch; -						if(tree_entry.isBlob()) { -							matching_path_patch = patches.find((patch) => patch.newFile().path() === tree_entry.path()); -						} -						else { -							matching_path_patch = patches.find((patch) => path.parse(patch.newFile().path()).dir.startsWith(tree_entry.path())); -						} - -						if(matching_path_patch) { -							obj.id = commit.sha(); -							obj.message = commit.message().replace(/\n/g, ""); -							obj.time = commit.date(); -						} -						return obj; -					}); -				}); -			} - -			return obj; -		}); -	}, Promise.resolve({})); -} - -module.exports.getLog = getLog; -module.exports.getRepos = getRepos; -module.exports.getRepoFile = getRepoFile; -module.exports.getCommit = getCommit; -module.exports.doesCommitExist = doesCommitExist; -module.exports.connectToGitHTTPBackend = connectToGitHTTPBackend; -module.exports.getTree = getTree;
\ No newline at end of file diff --git a/src/api/util.js b/src/api/util.js deleted file mode 100644 index aa31296..0000000 --- a/src/api/util.js +++ /dev/null @@ -1,45 +0,0 @@ -const fs = require("fs"); -const git = require("./git"); - -function verifyRepoName(dirty, base_dir) -{ -	return new Promise((resolve) => -	{ -		const is_valid_repo_name = /^[a-zA-Z0-9\\.\-_]+$/.test(dirty); -		if(!is_valid_repo_name) { -			resolve("ERR_REPO_REGEX"); -		} - -		fs.readdir(base_dir, (err, dir_content) => -		{ -			if(err) { -				resolve("ERR_REPO_NOT_FOUND"); -			} -			 -			dir_content = dir_content.filter(repo => repo.endsWith(".git")); -			if(!dir_content.includes(dirty + ".git")) { -				resolve("ERR_REPO_NOT_FOUND"); -			} -			 -			resolve(true); -		}); -	}); -} - -async function verifyCommitID(base_dir, repo, dirty) -{ -	if(!/^[a-fA-F0-9]+$/.test(dirty)) { -		return "ERR_COMMIT_REGEX"; -	} - -	const commit_exists = await git.doesCommitExist(base_dir, repo, dirty); - -	if(!commit_exists) { -		return "ERR_COMMIT_NOT_FOUND"; -	} - -	return true; -} - -module.exports.verifyRepoName = verifyRepoName; -module.exports.verifyCommitID = verifyCommitID;
\ No newline at end of file diff --git a/src/api/v1.js b/src/api/v1.js deleted file mode 100644 index 25a8019..0000000 --- a/src/api/v1.js +++ /dev/null @@ -1,136 +0,0 @@ -const git = require("./git"); -const util = require("./util"); - -module.exports = function (fastify, opts, done) -{ -	fastify.route({ -		method: "GET", -		path: "/info", -		handler: (req, reply) => -		{ -			reply.send({ data: opts.config.settings }); -		} -	}); -	fastify.route({ -		method: "GET", -		path: "/repos", -		handler: async (req, reply) => -		{ -			let repos = await git.getRepos(opts.config.settings.base_dir); - -			if(repos["error"]) { -				reply.code(500).send({ error: "Internal server error!" }); -				return; -			} - -			reply.send({ data: repos }); -		} -	}); - -	fastify.route({ -		method: "GET", -		path: "/repos/:repo", -		handler: async (req, reply) => -		{ -			const repo_verification = await util.verifyRepoName(req.params.repo, opts.config.settings.base_dir); -			if(repo_verification !== true) { -				if(repo_verification === "ERR_REPO_REGEX") { -					reply.code(400).send({ error: "Unacceptable git repository name!" }); -				} -				else if(repo_verification === "ERR_REPO_NOT_FOUND") { -					reply.code(404).send({ error: "Git repository not found!" }); -				} -			} - -			const repo = `${req.params.repo}.git`; -			const desc = await git.getRepoFile(opts.config.settings.base_dir, repo, "description"); - -			reply.send({ data: { name: req.params.repo, description: desc } }); -		} -	}); - -	fastify.register((fastify_repo, opts_repo, done_repo) => -	{ -		fastify_repo.addHook("onRequest", async (req, reply) => -		{ -			const repo_verification = await util.verifyRepoName(req.params.repo, opts.config.settings.base_dir); -			if(repo_verification !== true) { -				if(repo_verification === "ERR_REPO_REGEX") { -					reply.code(400).send({ error: "Unacceptable git repository name!" }); -				} -				else if(repo_verification === "ERR_REPO_NOT_FOUND") { -					reply.code(404).send({ error: "Git repository not found!" }); -				} -			} -		}); - -		fastify_repo.route({ -			method: "GET", -			path: "/log", -			handler: async (req, reply) => -			{ -				const log = await git.getLog(opts.config.settings.base_dir, req.params.repo + ".git"); -	 -				if(log["error"]) { -					if(typeof log["error"] === "string") { -						reply.code(500).send({ error: log["error"] }); -					} -	 -					switch(log["error"]) { -					case 404: -						reply.code(404).send({ error: "Git repository not found!" }); -					} -	 -					return; -				} -				reply.send({ data: log }); -			} -		}); - -		fastify_repo.route({ -			method: "GET", -			path: "/log/:commit", -			handler: async (req, reply) => -			{ -				const commit_verification = await util.verifyCommitID(opts.config.settings.base_dir, req.params.repo + ".git", req.params.commit); -				if(!commit_verification !== true) { -					if(commit_verification === "ERR_COMMIT_REGEX") { -						reply.code(400).send({ error: "Unacceptable commit id!" }); -					} -					else if(commit_verification === "ERR_COMMIT_NOT_FOUND") { -						reply.code(404).send({ error: "Commit not found!" }); -					} -				} -			 -				const commit = await git.getCommit(opts.config.settings.base_dir, req.params.repo, req.params.commit); -			 -				reply.send({ data: commit }); -			} -		}); - -		fastify_repo.route({ -			method: "GET", -			path: "/tree", -			handler: async (req, reply) => -			{ -				const tree_path = (req.query.length !== 0 && req.query.path) ? req.query.path : null; - -				const tree = await git.getTree(opts.config.settings.base_dir, req.params.repo, tree_path); - -				if(tree.error) { -					if(tree.error === 404) { -						reply.code(404).send({ error: "Path not found" }); -					} -					else { -						reply.code(500).send({ error: "Internal server error" }); -					} -				} -				reply.send({ data: tree }); -			} -		}); - -		done_repo(); -	}, { prefix: "/repos/:repo" }); - -	done(); -};
\ No newline at end of file diff --git a/src/app.js b/src/app.js deleted file mode 100644 index 8904219..0000000 --- a/src/app.js +++ /dev/null @@ -1,166 +0,0 @@ -const fastify = require("fastify")(); -const fastify_static = require('fastify-static'); -const api = require("./api/v1"); -const yaml = require('js-yaml'); -const fs = require('fs'); -const { exit } = require("process"); -const path = require("path"); -const util = require("./api/util"); -const git = require("./api/git"); - -const settings = yaml.load(fs.readFileSync(__dirname + "/../settings.yml", 'utf8')); -const settings_keys = Object.keys(settings); - -const mandatory_settings = [ "host", "port", "title", "about", "base_dir" ]; - -// Make sure that all the required settings are present -const settings_not_included = mandatory_settings.filter(x => !settings_keys.includes(x)); -if(settings_not_included.length !== 0) { -	console.log(`Error: settings.yml is missing ${(settings_not_included.length > 1) ? "keys" : "key"}:`); -	console.log(settings_not_included.join(", ")); -	exit(1); -} - -// Make sure that there's not an excessive amount of settings -const mandatory_not_included = settings_keys.filter(x => !mandatory_settings.includes(x)); -if(mandatory_not_included.length !== 0) { -	console.log(`Error: settings.yml includes ${(mandatory_not_included.length > 1) ? "pointless keys" : "a pointless key"}:`); -	console.log(mandatory_not_included.join(", ")); -	exit(1); -} - -// Make sure that the base directory specified in the settings actually exists -try { -	fs.readdirSync(settings["base_dir"]); -} -catch { -	console.error(`Error: Tried opening the base directory. No such directory: ${settings["base_dir"]}`); -	exit(1); -} - -const dist_dir = path.join(__dirname, "/../dist"); - -fastify.setNotFoundHandler({ -	preValidation: (req, reply, done) => done(), -	preHandler: (req, reply, done) => done() -}, function (req, reply) -{ -	reply.send("404: Not found"); -}); - -fastify.addContentTypeParser("application/x-git-upload-pack-request", (req, payload, done) => done(null, payload)); -   -fastify.register(fastify_static, { root: dist_dir }); -fastify.register(api, { prefix: "/api/v1", config: { settings: settings } }); - -fastify.route({ -	method: "GET", -	path: "/", -	handler: (req, reply) => reply.sendFile("app.html") -}); - -fastify.route({ -	method: "GET", -	path: "/app.html", -	handler: (req, reply) => reply.redirect("/") -}); - -fastify.register((fastify_repo, opts, done) => -{ -	fastify_repo.setNotFoundHandler({ -		preValidation: (req, reply, done) => done(), -		preHandler: (req, reply, done) => done() -	}, function (req, reply) -	{ -		reply.send("404: Not found"); -	}); - -	fastify_repo.addHook("onRequest", async (req, reply) => -	{ -		const repo_verification = await util.verifyRepoName(req.params.repo, settings.base_dir); -		if(repo_verification !== true) { -			if(repo_verification === "ERR_REPO_REGEX") { -				reply.code(400).send("Unacceptable git repository name!\n"); -			} -			else if(repo_verification === "ERR_REPO_NOT_FOUND") { -				reply.code(404).send("Git repository not found!\n"); -			} -		} -	}); - -	fastify_repo.route({ -		method: "GET", -		path: "/:page", -		handler: (req, reply) => -		{ -			if([ "log", "refs", "tree" ].includes(req.params.page)) { -				reply.sendFile("app.html"); -			} -		} -	}); -	 -	fastify_repo.route({ -		method: "GET", -		path: "/log/:subpage", -		handler: async (req, reply) => -		{ -			const commit_verification = await util.verifyCommitID(settings.base_dir, req.params.repo + ".git", req.params.subpage); -			console.log(commit_verification); -			if(commit_verification !== true) { -				reply.callNotFound(); -			} - -			reply.sendFile("app.html"); -		} -	}); - -	fastify_repo.route({ -		method: "GET", -		path: "/tree/*", -		handler: async (req, reply) => -		{ -			reply.sendFile("app.html"); -		} -	}); - -	fastify_repo.route({ -		method: "GET", -		path: "/info/refs", -		handler: (req, reply) => -		{ -			if(!req.query.service) { -				reply.code(403).send("Missing service query parameter\n"); -				return; -			} -			else if(req.query.service !== "git-upload-pack") { -				reply.code(403).send("Access denied!\n"); -				return; -			} -			else if(Object.keys(req.query).length !== 1) { -				reply.header("Content-Type", "application/x-git-upload-pack-advertisement"); -				reply.code(403).send("Too many query parameters!\n"); -				return; -			} - -			git.connectToGitHTTPBackend(settings["base_dir"], req, reply); -		} -	}); - -	fastify_repo.route({ -		method: "POST", -		path: "/git-upload-pack", -		handler: (req, reply) => git.connectToGitHTTPBackend(settings["base_dir"], req, reply) -	}); - -	done(); -}, { prefix: "/:repo" }); - -fastify.listen(settings["port"],(err, addr) => -{ -	if(err) { -		console.error(err); -		exit(1); -	} - -	console.log(`App is running on ${addr}`); -});
\ No newline at end of file diff --git a/src/frontend/App.vue b/src/frontend/App.vue deleted file mode 100644 index cbdce56..0000000 --- a/src/frontend/App.vue +++ /dev/null @@ -1,11 +0,0 @@ -<template> -	<div id="container" class="container-fluid px-0"> -		<router-view/> -	</div> -</template> - -<script> -export default { -	name: "App" -} -</script>
\ No newline at end of file diff --git a/src/frontend/app.html b/src/frontend/app.html deleted file mode 100644 index 348ca45..0000000 --- a/src/frontend/app.html +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE html> -<html> -	<head> -		<meta name="viewport" content="width=device-width, initial-scale=1.0"> -		<link rel="stylesheet" href="scss/style.scss"> -	</head> -	<body> -		<div id="app"></div> -		<script src="app.js"></script> -	</body> -</html>
\ No newline at end of file diff --git a/src/frontend/app.js b/src/frontend/app.js deleted file mode 100644 index 1b43bbe..0000000 --- a/src/frontend/app.js +++ /dev/null @@ -1,7 +0,0 @@ -import { createApp } from "vue/dist/vue.esm-bundler"; -import App from "./App.vue"; -import router from "./router"; - -createApp(App) -	.use(router) -	.mount("#app");
\ No newline at end of file diff --git a/src/frontend/components/BaseBackButton.vue b/src/frontend/components/BaseBackButton.vue deleted file mode 100644 index 64b1286..0000000 --- a/src/frontend/components/BaseBackButton.vue +++ /dev/null @@ -1,25 +0,0 @@ -<template> -	<div class="d-inline"> -		<router-link :to="to"> -			<svg -				xmlns="http://www.w3.org/2000/svg" id="back" -				height="24px" width="24px" -				viewBox="0 0 24 24" fill="#ffffff"> -				<path d="M0 0h24v24H0z" fill="none" /> -				<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /> -			</svg> -		</router-link> -	</div> -</template> - -<script> -export default { -	name: "BaseBackButton", -	props: { -		to: { -			type: String, -			required: true -		} -	} -} -</script>
\ No newline at end of file diff --git a/src/frontend/components/BaseBreadcrumb.vue b/src/frontend/components/BaseBreadcrumb.vue deleted file mode 100644 index df82968..0000000 --- a/src/frontend/components/BaseBreadcrumb.vue +++ /dev/null @@ -1,33 +0,0 @@ -<template> -	<nav aria-label="breadcrumb"> -		<ol class="breadcrumb"> -			<li -				v-for="(item, index) in items" class="breadcrumb-item" -				:key="index"> -				<router-link :to="item.path"> -					{{ item.name }} -				</router-link> -			</li> -			<li class="breadcrumb-item active" aria-current="page"> -				{{ activeItem }} -			</li> -		</ol> -	</nav> -</template> - - -<script> -export default { -	name: "BaseBreadcrumb", -	props: { -		items: { -			type: Array, -			required: true -		}, -		activeItem: { -			type: String, -			required: true -		} -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/components/CommitPatch.vue b/src/frontend/components/CommitPatch.vue deleted file mode 100644 index 2c815ff..0000000 --- a/src/frontend/components/CommitPatch.vue +++ /dev/null @@ -1,149 +0,0 @@ -<script> -import { h } from "vue"; -import hljs from "highlight.js"; -import hljs_languages from "../util/hljs-languages"; - -export default { -	name: "CommitPatch", -	props: { -		patch: { -			type: Object, -			required: true -		} -	}, -	setup(props) -	{ -		const commit_patch = [ -			h("div", { "class": "commit-file-header" }, [ -				h("span", { "class": "fw-bold"}, (props.patch["to"] === "/dev/null") ? props.patch["from"] : props.patch["to"]), -				h("span", (props.patch["to"] === "/dev/null") ? "Deleted" : "" ), -				h("div", { class: "commit-file-add-del" }, [ -					h("span", `+${ props.patch["additions"] }`), -					h("span", `-${ props.patch["deletions"] }`) -				]) -			]) -		]; - -		if(props.patch["too_large"] === false) { -			let all_hunks = props.patch["hunks"].map((hunk) => hunk["hunk"]); -			 -			const language = hljs_languages.find((lang) => lang["extensions"].some((extension) => props.patch["to"].endsWith(extension))); -			let highlighted = language ? hljs.highlight(language["name"], all_hunks.join("\n")) : hljs.highlightAuto(all_hunks.join("\n")); -			console.log(highlighted); -			highlighted = highlighted["value"].split("\n"); - -			const highlighted_hunks = []; -			let hunk_start = 0; -			all_hunks.forEach((hunk) => -			{ -				const hunk_row_cnt = hunk.split("\n").length; -				highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt)); -				hunk_start = hunk_start + hunk_row_cnt; -			}); - -			all_hunks = all_hunks.map((hunk) => hunk.split("\n")); - -			commit_patch.push(h("table", { cellspacing: "0px" }, [ -				h("tbody", [ -					props.patch["hunks"].map((hunk, hunk_index) => -					{ -						let new_offset = 0; -						let deleted_offset = 0; -						const multiline_comments = []; - -						return highlighted_hunks[hunk_index].map((line, line_index) => -						{ -							if(/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(all_hunks[hunk_index][line_index])) { -								new_offset++; -								deleted_offset++; -								return h("tr", { class: "commit-file-pos-change" }, [ -									h("td", { "patch-line-col-unsel": "..." }), -									h("td", { "patch-line-col-unsel": "..." }), -									h("td", { "patch-line-col-unsel": "..." }), -									h("td", [ -										h("code", all_hunks[hunk_index][line_index]) -									]) -								]); -							} -							else if(/^\\ No newline at end of file$/.test(all_hunks[hunk_index][line_index])) { -								new_offset++; -								deleted_offset++; -								return h("tr", { class: "commit-file-no-newline" }, [ -									h("td", ""), -									h("td", ""), -									h("td", ""), -									h("td", [ -										h("code", all_hunks[hunk_index][line_index]) -									]) -								]); -							} -							else { -								let first_td; -								let second_td; -								let third_td; - -								if(hunk['new'].includes(line_index)) { -									first_td = h("td", ""); -									second_td = h("td", { class: "line-highlight-new", "patch-line-col-unsel": Number(hunk["new_start"]) + line_index - new_offset }); -									third_td = h("td", { class: "line-new", "patch-line-col-unsel": "+" }); -									deleted_offset++; -								} -								else if(hunk['deleted'].includes(line_index)) { -									first_td = h("td", { "patch-line-col-unsel": Number(hunk["old_start"]) + line_index - deleted_offset }); -									second_td = h("td", { class: "line-highlight-deleted" }); -									third_td = h("td", { class: "line-deleted", "patch-line-col-unsel": "-" }); -									new_offset++; -								} -								else { -									first_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk["old_start"]) + line_index - deleted_offset }); -									second_td = h("td", { class: "line-unchanged", "patch-line-col-unsel": Number(hunk["new_start"]) + line_index - new_offset }); -									third_td = h("td", ""); -								} - -								let comment_open = line.match(/<span class="hljs-comment">/g); -								const comment_open_cnt = (comment_open !== null) ? comment_open.length : 0; -								comment_open = (comment_open !== null) ? comment_open[0] : ""; - -								let comment_close = line.match(/<\/span>/g); -								const comment_close_cnt = (comment_close !== null) ? comment_close.length : 0; -								comment_close = (comment_close !== null) ? comment_close[0] : ""; -						 -								if(comment_open_cnt > comment_close_cnt) { -									line = line + "</span>"; -									console.log("Öppning " + line); -									multiline_comments.push(comment_open); -								} -								else if(comment_open_cnt < comment_close_cnt && multiline_comments.length !== 0) { -									line = multiline_comments[multiline_comments.length - 1] + line; -									console.log("Stängning " + line + "	" + multiline_comments[multiline_comments.length - 1]); -									multiline_comments.pop(); -								} -								else if(multiline_comments.length !== 0) { -									line = multiline_comments[multiline_comments.length - 1] + line + "</span>"; -									console.log("Mitt i " + line); -								} -						 -								return h("tr", [ -									first_td, -									second_td, -									third_td, -									h("td", [ -										h("code", { innerHTML: line }) -									]) -								]); -							} -						}); -					}) -				]) -			])); -		} -		else { -			commit_patch.push(h("div", { class: "ps-3 pt-3 patch-too-large" }, [ -				h("span", "Patch is too large to display.") -			])); -		} - -		return () => h("div", { class: "commit-file" }, commit_patch); -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/components/HomeHeader.vue b/src/frontend/components/HomeHeader.vue deleted file mode 100644 index 9a0688d..0000000 --- a/src/frontend/components/HomeHeader.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> -	<div class="row mx-0"> -		<div id="header" class="col d-flex mt-3 ms-2"> -			<div class="d-inline ms-3"> -				<span id="title" class="fs-1">{{ title }}</span> -				<p id="about" class="mb-3 fs-4"> -					{{ about }} -				</p> -			</div> -		</div> -	</div> -</template> - -<script> -import { watch, reactive, toRefs } from "vue"; - -export default { -	name: "HomeHeader", -	setup() -	{ -		const state = reactive({ title: "", about: "" }); - -		watch(() => -		{ -			fetch(`${window.location.protocol}//${window.location.host}/api/v1/info`) -				.then((res) => res.json()) -				.then((data) => -				{ -					state.title = data["data"]["title"], -					state.about = data["data"]["about"] -				}); -		}); - -		return { -			... toRefs(state) -		}; -	} -} -</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryCloneDropdown.vue b/src/frontend/components/RepositoryCloneDropdown.vue deleted file mode 100644 index aaef5ef..0000000 --- a/src/frontend/components/RepositoryCloneDropdown.vue +++ /dev/null @@ -1,71 +0,0 @@ -<template> -	<div id="clone" class="d-flex align-items-center"> -		<div class="dropdown"> -			<button -				class="btn btn-primary btn-sm dropdown-toggle" type="button" -				id="dropdownMenuButton1" data-bs-toggle="dropdown" -				data-bs-auto-close="outside" aria-expanded="false"> -				Clone -			</button> -			<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark" aria-labelledby="dropdownMenuButton1"> -				<li class="pt-2"> -					<span class="ms-2 fs-5 fw-bold">Clone with HTTP</span> -					<label id="clone-url-copy"> -						<input -							type="text" :value="url" -							class="form-control form-control-sm ms-2 me-2" readonly> -						<svg -							xmlns="http://www.w3.org/2000/svg" height="18px" -							viewBox="0 0 24 24" width="18px" -							fill="#FFFFFF" @click="copyToClipboard"> -							<path d="M0 0h24v24H0z" fill="none" /> -							<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" /> -						</svg> -					</label> -				</li> -			</ul> -		</div> -	</div> -</template> - -<script> -import bootstrap from "bootstrap/dist/js/bootstrap.bundle"; - -export default { -	name: "RepositoryCloneDropdown", -	props: { -		repository: { -			type: String, -			required: true -		} -	}, -	methods: { -		copyToClipboard(event) -		{ -			const url_box = document.getElementById("clone").getElementsByTagName("input")[0]; - -			url_box.select(); -			url_box.setSelectionRange(0, 99999); -			document.execCommand("copy"); - -			event.stopPropagation(); - -			var exampleEl = document.getElementById('clone-url-copy').getElementsByTagName("svg")[0]; -			var tooltip = new bootstrap.Tooltip(exampleEl, { boundary: document.body, title: "Copied the URL", trigger: "manual" }); -			tooltip.show(); - -			const worker = new Worker("../util/worker.js"); -			worker.postMessage({ work: "sleep", time: 1700 }); - -			worker.onmessage = function() -			{ -				tooltip.hide(); -			} -		} -	}, -	setup(props) -	{ -		return { url: `${window.location.protocol}//${window.location.host}/${props.repository}` }; -	} -} -</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryHeader.vue b/src/frontend/components/RepositoryHeader.vue deleted file mode 100644 index 39ec00d..0000000 --- a/src/frontend/components/RepositoryHeader.vue +++ /dev/null @@ -1,51 +0,0 @@ -<template> -	<div class="row mx-0"> -		<div id="header" class="col d-flex mt-3 ms-2"> -			<BaseBackButton to="/" /> -			<div class="d-inline ms-3"> -				<span id="title" class="fs-1">{{ title }}</span> -				<p id="about" class="fs-4"> -					{{ about }} -				</p> -			</div> -		</div> -	</div> -</template> - -<script> -import BaseBackButton from "./BaseBackButton"; - -import { watch, reactive, toRefs } from "vue"; - -export default { -	name: "RepositoryHeader", -	components: { -		BaseBackButton -	}, -	props: { -		repository: { -			type: String, -			required: true -		} -	}, -	setup(props) -	{ -		const state = reactive({ title: "", about: "" }); - -		watch(() => -		{ -			fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${props.repository}`) -				.then((res) => res.json()) -				.then((data) => -				{ -					state.title = data["data"]["name"]; -					state.about = data["data"]["description"]; -				}); -		}); - -		return { -			... toRefs(state) -		}; -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryNavbar.vue b/src/frontend/components/RepositoryNavbar.vue deleted file mode 100644 index 53e1bfa..0000000 --- a/src/frontend/components/RepositoryNavbar.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> -	<div id="navbar" class="row mx-0"> -		<div id="repo-navbar" class="col ms-4 ps-4"> -			<nav class="navbar navbar-expand navbar-dark"> -				<div class="container-fluid px-0"> -					<div class="collapse navbar-collapse"> -						<ul class="navbar-nav align-items-center flex-fill"> -							<li -								v-for="(item, index) in nav_items" :key="index" -								class="nav-item"> -								<router-link -									class="nav-link fs-4" :class="{ active: activePage === item }" -									:aria-current="(activePage === item) ? 'page' : ''" :to="'/' + repository + '/' + item"> -									{{ item }} -								</router-link> -							</li> -							<li class="nav-item ms-auto me-4"> -								<RepositoryCloneDropdown :repository="repository" class="d-block" /> -							</li> -						</ul> -					</div> -				</div> -			</nav> -		</div> -	</div> -</template> - -<script> -import RepositoryCloneDropdown from "./RepositoryCloneDropdown"; - -export default { -	name: "RepositoryNavbar", -	props: { -		activePage: { -			type: String, -			required: true -		}, -		repository: { -			type: String, -			required: true -		} -	}, -	components: { -		RepositoryCloneDropdown -	}, -	data() -	{ -		return { -			nav_items: [ "log", "refs", "tree" ], -			url: `${window.location.protocol}//${window.location.host}/${this.repository}` -		}; -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryTreeBlob.vue b/src/frontend/components/RepositoryTreeBlob.vue deleted file mode 100644 index f287f47..0000000 --- a/src/frontend/components/RepositoryTreeBlob.vue +++ /dev/null @@ -1,154 +0,0 @@ -<template> -	<BaseBreadcrumb :items="[{ name: 'Tree', path: '/' + repository + '/tree' }]" :active-item="path" /> -	<table cellspacing="0px"> -		<tbody> -			<tr v-for="(line, index) in content_lines" :key="index"> -				<td :line="index + 1" /> -				<td> -					<code v-html="line" /> -				</td> -			</tr> -		</tbody> -	</table> -</template> - -<script> -import { ref } from "vue"; -import hljs from "highlight.js"; -import hljs_languages from "../util/hljs-languages"; -import path from "path"; - -export default { -	name: "RepositoryTreeBlob", -	props: { -		repository: { -			type: String, -			required: true -		}, -		path: { -			type: String, -			required: true -		}, -		content: { -			type: String, -			required: true -		} -	}, -	watch: { -		content() { -			this.initHighlightedContent(); -		} -	}, -	mounted() -	{ -		this.initHighlightedContent(); -	}, -	setup(props) -	{ -		const content_lines = ref([]); - -		const initHighlightedContent = async () => -		{ -			const language = hljs_languages.find((lang) => lang["extensions"].some((extension) => path.extname(props.path) === extension)); -			let highlighted = language ? hljs.highlight(language["name"], props.content) : hljs.highlightAuto(props.content); -			 -			content_lines.value = highlighted.value.split("\n"); -		}; - -		return { content_lines, initHighlightedContent }; - -		/* -		Console.log(props.content); -		const content_lines = props.content.split("\n"); - -		const language = hljs_languages.find((lang) => lang["extensions"].some((extension) => path.extname(props.path) === extension)); -		let highlighted = language ? hljs.highlight(language["name"], props.content) : hljs.highlightAuto(props.content); -		console.log(highlighted.value); -		Let all_hunks = props.patch["hunks"].map((hunk) => hunk["hunk"]); -		 -		const language = hljs_languages.find((lang) => lang["extensions"].some((extension) => props.patch["to"].endsWith(extension))); -		let highlighted = language ? hljs.highlight(language["name"], all_hunks.join("\n")) : hljs.highlightAuto(all_hunks.join("\n")); -		console.log(highlighted); -		highlighted = highlighted["value"].split("\n"); - -		const highlighted_hunks = []; -		let hunk_start = 0; -		all_hunks.forEach((hunk) => -		{ -			const hunk_row_cnt = hunk.split("\n").length; -			highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt)); -			hunk_start = hunk_start + hunk_row_cnt; -		}); - -		all_hunks = all_hunks.map((hunk) => hunk.split("\n")); - -		return h("table", { cellspacing: "0px" }, [ -			h("tbody", [ -				Props.patch["hunks"].map((hunk, hunk_index) => -				{ -					const multiline_comments = []; - -					return highlighted_hunks[hunk_index].map((line, line_index) => -					{ -						else { -							let first_td; -							let second_td; -							let third_td; - -							if(hunk['new'].includes(line_index)) { -								first_td = h("td", ""); -								second_td = h("td", { class: "line-highlight-new" }, Number(hunk["new_start"]) + line_index - new_offset); -								third_td = h("td", { class: "line-new" }, "+"); -								deleted_offset++; -							} -							else if(hunk['deleted'].includes(line_index)) { -								first_td = h("td", Number(hunk["old_start"]) + line_index - deleted_offset); -								second_td = h("td", { class: "line-highlight-deleted" }); -								third_td = h("td", { class: "line-deleted" }, "-"); -								new_offset++; -							} -							else { -								first_td = h("td", { class: "line-unchanged" }, Number(hunk["old_start"]) + line_index - deleted_offset); -								second_td = h("td", { class: "line-unchanged" }, Number(hunk["new_start"]) + line_index - new_offset); -								third_td = h("td", ""); -							} - -							let comment_open = line.match(/<span class="hljs-comment">/g); -							const comment_open_cnt = (comment_open !== null) ? comment_open.length : 0; -							comment_open = (comment_open !== null) ? comment_open[0] : ""; - -							let comment_close = line.match(/<\/span>/g); -							const comment_close_cnt = (comment_close !== null) ? comment_close.length : 0; -							comment_close = (comment_close !== null) ? comment_close[0] : ""; -					 -							if(comment_open_cnt > comment_close_cnt) { -								line = line + "</span>"; -								console.log("Öppning " + line); -								multiline_comments.push(comment_open); -							} -							else if(comment_open_cnt < comment_close_cnt && multiline_comments.length !== 0) { -								line = multiline_comments[multiline_comments.length - 1] + line; -								console.log("Stängning " + line + "	" + multiline_comments[multiline_comments.length - 1]); -								multiline_comments.pop(); -							} -							else if(multiline_comments.length !== 0) { -								line = multiline_comments[multiline_comments.length - 1] + line + "</span>"; -								console.log("Mitt i " + line); -							} -					 -							return h("tr", [ -								first_td, -								second_td, -								third_td, -								h("td", [ -									h("code", { innerHTML: line }) -								]) -							]); -						} -					}); -				}) -			]) -		]);*/ -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryTreeTree.vue b/src/frontend/components/RepositoryTreeTree.vue deleted file mode 100644 index 70c63eb..0000000 --- a/src/frontend/components/RepositoryTreeTree.vue +++ /dev/null @@ -1,84 +0,0 @@ -<template> -	<table id="tree" class="fs-5"> -		<thead> -			<tr> -				<th>Name</th> -				<th>Last commit</th> -				<th>Last updated</th> -			</tr> -		</thead> -		<tbody> -			<tr v-if="path !== ''" @click="$router.go(-1)"> -				<td -					class="d-flex align-items-center"> -					<div class="tree-entry-padding" /> -					.. -				</td> -				<td /> -				<td /> -			</tr> -			<tr -				v-for="(entry, entry_name, index) in tree" :key="index" -				@click="$router.push(`/${repository}/tree${path ? '/' + path : ''}/${entry_name}`)"> -				<td class="d-flex align-items-center"> -					<svg -						xmlns="http://www.w3.org/2000/svg" height="18px" -						viewBox="0 0 24 24" width="18px" -						fill="#FFFFFF" v-if="entry['type'] === 'tree'" -						preserveAspectRatio="xMidYMin"> -						<path d="M0 0h24v24H0z" fill="none" /> -						<path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" /> -					</svg> -					<span v-else class="tree-entry-padding" /> -					<a @click="stopClick" :href="`/${repository}/tree${path ? '/' + path : ''}/${entry_name}`">{{ entry_name }}</a> -				</td> -				<td> -					<a @click="routeToCommit(entry.last_commit.id, $event)" :href="`/${repository}/log/${entry.last_commit.id}`"> -						{{ entry.last_commit.message }} -					</a> -				</td> -				<td> -					{{ getPrettyLastUpdated(entry.last_commit.time) }} -				</td> -			</tr> -		</tbody> -	</table> -</template> - -<script> -const { formatDistance } = require('date-fns'); - -export default { -	name: "RepositoryTreeTree", -	props: { -		repository: { -			type: String, -			required: true -		}, -		path: { -			type: String, -			required: true -		}, -		tree: { -			type: Object, -			required: true -		} -	}, -	methods: { -		stopClick(event) -		{ -			event.preventDefault(); -		}, -		routeToCommit(commit_id, event) -		{ -			event.stopPropagation(); -			event.preventDefault(); -			this.$router.push(`/${this.repository}/log/${commit_id}`); -		}, -		getPrettyLastUpdated(date) -		{ -			return formatDistance(new Date(), new Date(date)); -		} -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/router/index.js b/src/frontend/router/index.js deleted file mode 100644 index fc332cd..0000000 --- a/src/frontend/router/index.js +++ /dev/null @@ -1,46 +0,0 @@ -import { createRouter, createWebHistory } from "vue-router"; -import Home from "../views/Home"; -import Repository from "../views/Repository"; -import RepositoryLog from "../views/RepositoryLog"; -import RepositoryCommit from "../views/RepositoryCommit"; -import RepositoryTree from "../views/RepositoryTree"; - -const routes = [ -	{ -		name: "Home", -		path: "/", -		component: Home -	}, -	{ -		name: "Repository", -		path: '/:repo([a-zA-Z0-9\\.\\-_]+)', -		component: Repository, -		props: route => ({ repository: route.params.repo }), -		children: [ -			{ -				name: "Repository Log", -				path: "log", -				component: RepositoryLog -			}, -			{ -				name: "Commit", -				path: "log/:commit([a-fA-F0-9]{40}$)", -				component: RepositoryCommit, -				props: route => ({ commit: route.params.commit }) -			}, -			{ -				name: "Tree Entry", -				path: "tree/:path*", -				component: RepositoryTree, -				props: route => ({ pathArr: route.params.path ? route.params.path : [] }) -			} -		] -	} -]; - -const router = createRouter({ -	history: createWebHistory(process.env.BASE_URL), -	routes -}); - -export default router;
\ No newline at end of file diff --git a/src/frontend/scss/abstracts/_colors.scss b/src/frontend/scss/abstracts/_colors.scss deleted file mode 100644 index 3c05336..0000000 --- a/src/frontend/scss/abstracts/_colors.scss +++ /dev/null @@ -1,10 +0,0 @@ -$primary: #023E8A; -$primary-light: #0077b6; -$secondary: #F48C06; -$success: #40916C; -$new: #06d6a0; -$danger: #D00000; -$text: #ffffff; -$text-gray: #6c757d; -$background: #121212; -$not-selected: #adb5bd;
\ No newline at end of file diff --git a/src/frontend/scss/abstracts/_fonts.scss b/src/frontend/scss/abstracts/_fonts.scss deleted file mode 100644 index 6af5233..0000000 --- a/src/frontend/scss/abstracts/_fonts.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Oxygen:wght@300&display=swap'); - -$title: 'Oxygen', sans-serif; -$primary: 'Open Sans', sans-serif;
\ No newline at end of file diff --git a/src/frontend/scss/style.scss b/src/frontend/scss/style.scss deleted file mode 100644 index 8cca066..0000000 --- a/src/frontend/scss/style.scss +++ /dev/null @@ -1,396 +0,0 @@ -@use "abstracts/colors"; -@use "abstracts/fonts"; - -@import "../../../node_modules/bootstrap/scss/functions"; -@import "../../../node_modules/bootstrap/scss/variables"; -@import "../../../node_modules/bootstrap/scss/mixins"; - -$theme-colors: ( -  "primary":    colors.$primary, -  "secondary":  colors.$secondary, -  "success":    colors.$success, -  "info":       $info, -  "warning":    $warning, -  "danger":     colors.$danger, -  "light":      $light, -  "dark":       $dark -); - -$font-size-base: 0.75rem; - -$h1-font-size:                $font-size-base * 2.5; -$h2-font-size:                $font-size-base * 2; -$h3-font-size:                $font-size-base * 1.75; -$h4-font-size:                $font-size-base * 1.5; -$h5-font-size:                $font-size-base * 1.125; -$h6-font-size:                $font-size-base; - -$font-sizes: ( -  1: $h1-font-size, -  2: $h2-font-size, -  3: $h3-font-size, -  4: $h4-font-size, -  5: $h5-font-size, -  6: $h6-font-size -); - -$navbar-nav-link-padding-x: 0.5rem; - -$btn-box-shadow: none; -$btn-active-box-shadow: none; -$btn-focus-box-shadow: none; - -$input-bg: lighten(#000000, 12%); -$input-disabled-bg: lighten(#000000, 12%); -$input-color: colors.$text; -$input-focus-color: colors.$text; -$input-focus-box-shadow: none; -$input-disabled-border-color: lighten(#000000, 50%); -$input-height-sm: auto; - -$dropdown-dark-bg: lighten(#000000, 10%); - -@import "../../../node_modules/bootstrap/scss/breadcrumb"; -@import "../../../node_modules/bootstrap/scss/tooltip"; -@import "../../../node_modules/bootstrap/scss/buttons"; -@import "../../../node_modules/bootstrap/scss/dropdown"; -@import "../../../node_modules/bootstrap/scss/forms"; -@import "../../../node_modules/bootstrap/scss/utilities"; -@import "../../../node_modules/bootstrap/scss/utilities/api"; -@import "../../../node_modules/bootstrap/scss/nav"; -@import "../../../node_modules/bootstrap/scss/navbar"; - -$table-cell-padding-x: 1rem; -$table-cell-padding-y: 0.2rem; - -$table-variants: ( -  "primary":    shift-color($primary, $table-bg-scale), -  "secondary":  shift-color($secondary, $table-bg-scale), -  "success":    shift-color($success, $table-bg-scale), -  "info":       shift-color($info, $table-bg-scale), -  "warning":    shift-color($warning, $table-bg-scale), -  "danger":     shift-color($danger, $table-bg-scale), -  "light":      $light, -  "dark":       colors.$background, -); - -@import "../../../node_modules/bootstrap/scss/tables"; - -@import "../../../node_modules/bootstrap/scss/containers"; -@import "../../../node_modules/bootstrap/scss/grid"; - -@import "../../../node_modules/highlight.js/scss/srcery.scss"; - -body { -	background-color: colors.$background; -	color: colors.$text; -	font-family: fonts.$primary; -	margin: 0px; -} - -ul { -	list-style-type: none; -	padding: 0; -} - -li { -	div { -		h2 { -			margin: 0px; -		} -	} -} - -p { -	margin: 0px; -} - -#title { -	font-family: fonts.$title; -	font-weight: 300; -	line-height: 0.6; -} - -#about { -	font-weight: 300; -	padding-left: 1px; -} - -.form-control { -	width: auto; -} - -#clone { -	margin-left: auto; -	margin-right: 40px; -} - -#clone-url-copy { -	position: relative; -	height: 30px; -	display: block; -    text-align: left; -    margin: 5px auto; -	input { -		display: inline-block; -    	padding-right: 30px; -	} -	svg { -		content: ""; -		position: absolute; -		right: 12px; -		top: 7px; -		bottom: 0; -		width: 18px; -		fill: colors.$not-selected; -		&:hover { -			fill: colors.$text; -		} -	} -} - -#projects-search { -	align-items: center; -	form { -		display: flex; -		align-items: center; -		height: 35px; -		input[type=search] { -			margin-right: 15px; -		} -	} -} - -#repos { -	margin-top: 25px; -	li { -		margin-bottom: 25px; -	} -} - -.repo-last-updated { -	display: block; -	font-weight: 300; -	font-style: italic; -} - -input[type=submit] { -	background-color: colors.$primary; -	color: colors.$text; -	font-size: 1rem; -	border: 0px; -	border-radius: 7px; -	padding: 8px 15px 8px 15px; -} - -a { -	color: colors.$text; -	text-decoration: none; -	&:hover { -		color: colors.$primary-light; -	} -} - -.breadcrumb { -	li { -		margin-bottom: 0.5rem; -	} -} - -#commit-info { -	margin-bottom: 2rem; -	tbody tr { -		td { -			padding: 0px; -			padding-right: 10px; -		} -	} -} - -.commit-file { -	margin-bottom: 50px; -	table { -		padding-top: 15px; -		tbody tr td { -			padding: 0px; -			padding-left: 8px; -			vertical-align: top; -			&:nth-child(2) { -				padding-right: 7px; -			} -			&:nth-child(3) { -				padding-right: 15px; -			} -		} -	} -} - -.commit-file-add-del { -	margin-left: auto; -	margin-right: 23px; -	span { -		margin-right: 10px !important; -		font-weight: 700; -		&:nth-child(1) { -			color: colors.$new; -		} -	} -} - -.commit-file-pos-change { -	color: colors.$text-gray; -} - -.commit-file-no-newline { -	color: colors.$text-gray; -} - -.line-new { -	color: colors.$new; -} -.line-deleted { -	color: colors.$danger; -} - -.line-unchanged { -	color: colors.$text-gray; -} - -[patch-line-col-unsel]::before { -	content: attr(patch-line-col-unsel); -} - -.line-highlight-new { -	border-right: 1px solid colors.$new; -} -.line-highlight-deleted { -	border-right: 1px solid colors.$danger; -} - -code { -	white-space: pre-wrap; -	word-wrap: anywhere; -} - -.commit-file-header { -	display: flex; -	background-color: lighten(#000000, 14%); -	padding: 10px; -	span { -		margin-right: 30px; -		&:nth-child(2) { -			color: colors.$danger; -		} -	} -} - -#back:hover { -	fill: colors.$primary-light; -} - -#navbar { -	line-height: 0; -} - -th { -	text-align: start; -} - -.commit-info-title { -	color: colors.$secondary; -	padding-right: 30px; -	width: 20px; -} - -.patch-too-large { -	font-weight: 600; -} - -.dropdown-item { -	width: auto !important; -} - -.btn-primary { -	color: colors.$text; -	&:hover { -		background-color: colors.$primary-light; -	} -} - - -.btn-check:checked + .btn-primary:focus, -.btn-check:active + .btn-primary:focus, -.btn-primary:active:focus, -.btn-primary.active:focus, -.show > .btn-primary.dropdown-toggle:focus { -	box-shadow: none; -} - -.btn-check:focus + .btn-primary, -.btn-primary:focus { -	box-shadow: none; -} - -#tree { -	border-spacing: 0; -	th { -		padding-bottom: 5px; -		color: colors.$secondary; -	} -	tbody tr:hover { -		background-color: lighten(colors.$background, 10%); -	} -	td { -		padding-top: 5px; -		padding-bottom: 5px; -		padding-right: 2vw; -		&:nth-child(2) a, &:nth-child(3) { -			font-weight: 300; -		} -	} -	.tree-entry-padding, svg { -		width: 18px; -		padding-right: 5px; -	} -	a {	 -		padding-right: 18px; -	} -} - -[line]::before { -	content: attr(line); -	padding-right: 10px; -} - -@include media-breakpoint-down(sm) { -	.commit-file table tbody tr td { -		padding-left: 4px; -		&:nth-child(2) { -			padding-right: 4px; -		} -		&:nth-child(3) { -			padding-right: 5px; -		} -	} -	.table > :not(caption) > * > * { -		padding: 0.1rem; -	} -} - -@media (max-width: 1200px) { -	.fs-1 { -		font-size: calc(1.375rem + 0.667vw) !important; -	} -	.fs-2 { -		font-size: calc(1.325rem + 1.584vw) !important; -	} -	.fs-3 { -		font-size: calc(1.3rem + 0.017vw) !important; -	} -	.fs-4 { -		font-size: calc(0.82rem + 0.4vw) !important; -	} -	.fs-5 { -		font-size: calc(0.65rem + 0.25vw) !important; -	} -}
\ No newline at end of file diff --git a/src/frontend/util/hljs-languages.js b/src/frontend/util/hljs-languages.js deleted file mode 100644 index c8576e0..0000000 --- a/src/frontend/util/hljs-languages.js +++ /dev/null @@ -1,45 +0,0 @@ -const languages = [ -	{ "name": "arduino", "extensions": [ ".ino" ]}, -	{ "name": "actionscript", "extensions": [ ".as" ]}, -	{ "name": "bash", "extensions": [ ".sh", ".zsh" ]}, -	{ "name": "csharp", "extensions": [ ".cs" ]}, -	{ "name": "c", "extensions": [ ".c", ".h" ]}, -	{ "name": "cpp", "extensions": [ ".cpp", ".hpp" ]}, -	{ "name": "cmake", "extensions": [ "cmake.in" ]}, -	{ "name": "css", "extensions": [ ".css" ]}, -	{ "name": "d", "extensions": [ ".d" ]}, -	{ "name": "dos", "extensions": [ ".bat", ".cmd" ]}, -	{ "name": "dockerfile", "extensions": [ "dockerfile", "Dockerfile" ]}, -	{ "name": "go", "extensions": [ ".go" ]}, -	{ "name": "gradle", "extensions": [ ".gradle" ]}, -	{ "name": "xml", "extensions": [ ".xml", ".html", ".xhtml", ".rss", ".atom", ".xjb", ".xsd", ".xsl", ".plist", ".svg" ]}, -	{ "name": "haskell", "extensions": [ ".hs" ]}, -	{ "name": "ini", "extensions": [ ".ini", ".toml" ]}, -	{ "name": "json", "extensions": [ ".json" ]}, -	{ "name": "java", "extensions": [ ".java", ".jsp" ]}, -	{ "name": "javascript", "extensions": [ ".js", ".jsx" ]}, -	{ "name": "kotlin", "extensions": [ ".kt" ]}, -	{ "name": "lua", "extensions": [ ".lua" ]}, -	{ "name": "makefile", "extensions": [ "makefile", "Makefile" ]}, -	{ "name": "markdown", "extensions": [ ".md" ]}, -	{ "name": "objectivec", "extensions": [ ".m", ".mm", ".M" ]}, -	{ "name": "php", "extensions": [ ".php" ]}, -	{ "name": "perl", "extensions": [ ".pl", ".pm" ]}, -	{ "name": "plaintext", "extensions": [ ".txt" ]}, -	{ "name": "pgsql", "extensions": [ ".pgsql" ]}, -	{ "name": "powershell", "extensions": [ ".ps", ".ps1" ]}, -	{ "name": "python", "extensions": [ ".py" ]}, -	{ "name": "ruby", "extensions": [ ".rb" ]}, -	{ "name": "rust", "extensions": [ ".rs" ]}, -	{ "name": "scss", "extensions": [ ".scss" ]}, -	{ "name": "sql", "extensions": [ ".sql" ]}, -	{ "name": "swift", "extensions": [ ".swift" ]}, -	{ "name": "typescript", "extensions": [ ".ts" ]}, -	{ "name": "vbnet", "extensions": [ ".vb" ]}, -	{ "name": "vba", "extensions": [ ".vba" ]}, -	{ "name": "vbscript", "extensions": [ ".vbs" ]}, -	{ "name": "vim", "extensions": [ ".vim" ]}, -	{ "name": "yml", "extensions": [ ".yml" ]} -]; - -export default languages;
\ No newline at end of file diff --git a/src/frontend/util/worker.js b/src/frontend/util/worker.js deleted file mode 100644 index e50743a..0000000 --- a/src/frontend/util/worker.js +++ /dev/null @@ -1,6 +0,0 @@ -onmessage = function(e) -{ -	if(e.data.work === "sleep") { -		setTimeout(() => postMessage("done"), e.data.time); -	} -};
\ No newline at end of file diff --git a/src/frontend/views/Home.vue b/src/frontend/views/Home.vue deleted file mode 100644 index e3746c7..0000000 --- a/src/frontend/views/Home.vue +++ /dev/null @@ -1,62 +0,0 @@ -<template> -	<HomeHeader /> -	<div class="row mx-0"> -		<div id="projects-header" class="col ms-4"> -			<p class="fs-1"> -				Projects -			</p> -		</div> -		<div id="projects-search" class="col d-flex justify-content-end"> -			<form> -				<input type="search" name="q"> -				<input type="submit" value="Search"> -			</form> -		</div> -	</div> -	<div class="row mx-0"> -		<div class="col ms-4"> -			<ul id="repos"> -				<li v-for="(project, project_name, index) in projects" :key="index"> -					<div v-if="(search !== null && project_name.includes(search)) || search == null"> -						<p class="fs-3"> -							<router-link :to="project_name"> -								{{ project_name }} -							</router-link> -						</p> -						<span class="repo-last-updated fs-5">Last updated about {{ project["last_updated"] }} ago</span> -						<span class="fs-5">{{ project["description"] }}</span> -					</div> -				</li> -			</ul> -		</div> -	</div> -</template> - -<script> -import HomeHeader from "../components/HomeHeader"; -import { watch, reactive, toRefs } from "vue"; - -export default { -	name: "Home", -	components: { -		HomeHeader -	}, -	setup() -	{ -		const state = reactive({ projects: {}, search: "" }); - -		watch(() => -		{ -			fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos`) -				.then((res) => res.json()) -				.then((data) => state.projects = data["data"]); -		}); - -		state.search = (new URLSearchParams(window.location.search)).get("q"); - -		return { -			... toRefs(state) -		}; -	} -} -</script>
\ No newline at end of file diff --git a/src/frontend/views/Repository.vue b/src/frontend/views/Repository.vue deleted file mode 100644 index 8863529..0000000 --- a/src/frontend/views/Repository.vue +++ /dev/null @@ -1,29 +0,0 @@ -<template> -	<RepositoryHeader :repository="repository" /> -	<router-view :repository="repository" /> -</template> - -<script> -import RepositoryHeader from "../components/RepositoryHeader"; - -export default { -	name: "Repository", -	components: { -		RepositoryHeader -	}, -	props: { -		repository: { -			type: String, -			required: true -		} -	}, -	created() -	{ -		if(/^\/[a-zA-Z0-9.\-_]+[/]?$/.test(window.location.pathname)) { -			this.$router.push({ path: `${window.location.pathname}${( window.location.pathname.endsWith("/") ) ? "log" : "/log"}`, replace: true}); -		} - -		console.log(this.repository); -	} -} -</script>
\ No newline at end of file diff --git a/src/frontend/views/RepositoryCommit.vue b/src/frontend/views/RepositoryCommit.vue deleted file mode 100644 index d3ba174..0000000 --- a/src/frontend/views/RepositoryCommit.vue +++ /dev/null @@ -1,89 +0,0 @@ -<template> -	<RepositoryNavbar active-page="log" :repository="repository" /> -	<div class="row mx-0"> -		<div class="col ms-2 ps-4 ps-sm-5 fs-5 vld-parent"> -			<BaseBreadcrumb :items="[{ name: 'Log', path: '/' + repository + '/log' }]" :active-item="commit" /> -			<Loading -				v-model:active="is_loading" :height="24" -				:width="24" color="#ffffff" -				:opacity="0" /> -			<table id="commit-info" class="table table-dark"> -				<tbody> -					<tr> -						<td class="commit-info-title"> -							Author -						</td> -						<td>{{ commit_data["author"] }}</td> -					</tr> -					<tr> -						<td class="commit-info-title"> -							Date -						</td> -						<td>{{ commit_data["date"] }}</td> -					</tr> -					<tr> -						<td class="commit-info-title"> -							Message -						</td> -						<td>{{ commit_data["message"] }}</td> -					</tr> -				</tbody> -			</table> - -			<template -				v-for="(patch, index) in commit_data['patches']" :key="index"> -				<CommitPatch :patch="patch" /> -			</template> -		</div> -	</div> -</template> - -<script> -import RepositoryNavbar from "../components/RepositoryNavbar"; -import CommitPatch from "../components/CommitPatch"; -import BaseBreadcrumb from "../components/BaseBreadcrumb"; -import Loading from "vue-loading-overlay"; -import 'vue-loading-overlay/dist/vue-loading.css'; -import { watch, reactive, toRefs } from "vue"; -import { format } from "date-fns"; - -export default { -	name: "RepositoryCommit", -	components: { -		RepositoryNavbar, -		CommitPatch, -		Loading, -		BaseBreadcrumb -	}, -	props: { -		repository: { -			type: String, -			required: true -		}, -		commit: { -			type: String, -			required: true -		} -	}, -	setup(props) -	{ -		const state = reactive({ commit_data: {}, is_loading: true }); - -		watch(() => -		{ -			fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${props.repository}/log/${props.commit}`) -				.then((res) => res.json()) -				.then((data) => -				{ -					data["data"]["date"] = format(new Date(data["data"]["date"]), "yyyy-MM-dd hh:mm"); -					state.commit_data = data["data"]; -					state.is_loading = false; -				}); -		}); - -		return { -			... toRefs(state) -		}; -	} -}; -</script> diff --git a/src/frontend/views/RepositoryLog.vue b/src/frontend/views/RepositoryLog.vue deleted file mode 100644 index 3adb6c2..0000000 --- a/src/frontend/views/RepositoryLog.vue +++ /dev/null @@ -1,91 +0,0 @@ -<template> -	<RepositoryNavbar active-page="log" :repository="repository" /> -	<div class="row mx-0 vld-parent"> -		<Loading -			v-model:active="is_loading" :height="24" -			:width="24" color="#ffffff" -			:opacity="0" /> -		<div class="col ms-4 ps-4 ps-sm-5 mt-3"> -			<table id="log" class="table table-dark fs-5"> -				<thead> -					<tr> -						<th class="text-secondary"> -							Subject -						</th> -						<th class="text-secondary"> -							Author -						</th> -						<th class="text-secondary"> -							Date -						</th> -						<th class="text-secondary"> -							Files -						</th> -						<th class="text-secondary"> -							Del/Add -						</th> -					</tr> -				</thead> -				<tbody> -					<tr v-for="(commit, index) in commits" :key="index"> -						<td> -							<router-link :to="'log/' + commit['commit']"> -								{{ commit["message"] }} -							</router-link> -						</td> -						<td>{{ commit["author_name"] }}</td> -						<td>{{ format(new Date(commit["date"]), "yyyy-MM-dd hh:mm") }}</td> -						<td>{{ commit["files_changed"] }}</td> -						<td><span class="text-danger">-{{ commit["deletions"] }}</span> / <span class="text-success">+{{ commit["insertions"] }}</span></td> -					</tr> -				</tbody> -			</table> -		</div> -	</div> -</template> - -<script> -import RepositoryNavbar from "../components/RepositoryNavbar"; -import Loading from "vue-loading-overlay"; -import 'vue-loading-overlay/dist/vue-loading.css'; -import { format } from "date-fns"; -import { watch, reactive, toRefs } from "vue"; - -export default { -	name: "RepositoryLog", -	components: { -		RepositoryNavbar, -		Loading -	}, -	props: { -		repository: { -			type: String, -			required: true -		} -	}, -	data() -	{ -		return { -			format: format -		}; -	}, -	setup(props) -	{ -		const state = reactive({ commits: {}, is_loading: true }); - -		watch(() => -		{ -			fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${props.repository}/log`) -				.then((res) => res.json()) -				.then((data) => { -					state.commits = data["data"]; -					state.is_loading = false; -				}); -		}); - -		return { -			... toRefs(state) -		}; -	} -}; -</script>
\ No newline at end of file diff --git a/src/frontend/views/RepositoryTree.vue b/src/frontend/views/RepositoryTree.vue deleted file mode 100644 index dc2c067..0000000 --- a/src/frontend/views/RepositoryTree.vue +++ /dev/null @@ -1,110 +0,0 @@ -<template> -	<RepositoryNavbar active-page="tree" :repository="repository" /> -	<div class="row mx-0 vld-parent"> -		<Loading -			v-model:active="is_loading" :height="24" -			:width="24" color="#ffffff" -			:opacity="0" /> -		<div class="col ms-4 ps-4 ps-sm-5 mt-3 fs-5"> -			<BaseBreadcrumb -				:items="[{ name: repository, path: '/' + repository + '/tree' }].concat(pathArr.slice(0, -1).map((path_part, index) => -				{ -					return { -						name: path_part, -						path: '/' + repository + '/tree/' + pathArr.slice(0, index + 1).join('/') -					} -				}))" :active-item="pathArr[pathArr.length - 1]" /> -			<RepositoryTreeTree -				:repository="repository" :path="path" -				:tree="tree" v-if="type === 'tree'" /> -			<RepositoryTreeBlob -				:repository="repository" :path="path" -				:content="blob_content" v-else /> -		</div> -	</div> -</template> - -<script> -import RepositoryNavbar from "../components/RepositoryNavbar"; -import RepositoryTreeTree from "../components/RepositoryTreeTree"; -import RepositoryTreeBlob from "../components/RepositoryTreeBlob"; -import BaseBreadcrumb from "../components/BaseBreadcrumb"; -import Loading from "vue-loading-overlay"; -import 'vue-loading-overlay/dist/vue-loading.css'; -import { ref } from "vue"; - -export default { -	name: "RepositoryTree", -	components: { -		RepositoryNavbar, -		Loading, -		RepositoryTreeTree, -		RepositoryTreeBlob, -		BaseBreadcrumb -	}, -	props: { -		repository: { -			type: String, -			required: true -		}, -		pathArr: { -			type: Array, -			required: true -		} -	}, -	watch: { -		pathArr() -		{ -			this.fetchTree(); -		} -	}, -	setup(props) -	{ -		const type = ref(""); -		const tree = ref({}); -		const blob_content = ref(""); -		const is_loading = ref(true); -		const path = ref(""); - -		const fetchTree = async () => -		{ -			path.value = props.pathArr ? props.pathArr.join("/") : undefined; -			const data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${props.repository}/tree${path.value ? "?path=" + path.value : ""}`)).json(); -			 -			console.log(path.value); -			type.value = data["data"]["type"]; - -			if(data["data"]["type"] === "tree") { -				const tree_data = data["data"]["tree"]; - -				let tree_trees = Object.entries(tree_data).filter((entry) => entry[1].type === "tree"); -				tree_trees = tree_trees.sort((a, b) => a[0].localeCompare(b[0])); - -				let tree_blobs = Object.entries(tree_data).filter((entry) => entry[1].type === "blob"); -				tree_blobs = tree_blobs.sort((a, b) => a[0].localeCompare(b[0])); - -				tree.value = Object.fromEntries(tree_trees.concat(tree_blobs)); -			} -			else { -				blob_content.value = data["data"]["content"]; -			} - -			is_loading.value = false; -		}; - -		return { -			type, -			tree, -			blob_content, -			is_loading, -			path, -			fetchTree -		}; -	}, -	mounted() -	{ -		console.log("VAFAAAN öaöaöaö"); -		this.fetchTree(); -	} -}; -</script>
\ No newline at end of file  | 
