aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/git.js415
-rw-r--r--src/api/util.js45
-rw-r--r--src/api/v1.js136
-rw-r--r--src/app.js166
-rw-r--r--src/frontend/App.vue11
-rw-r--r--src/frontend/app.html11
-rw-r--r--src/frontend/app.js7
-rw-r--r--src/frontend/components/BaseBackButton.vue25
-rw-r--r--src/frontend/components/BaseBreadcrumb.vue33
-rw-r--r--src/frontend/components/CommitPatch.vue149
-rw-r--r--src/frontend/components/HomeHeader.vue39
-rw-r--r--src/frontend/components/RepositoryCloneDropdown.vue71
-rw-r--r--src/frontend/components/RepositoryHeader.vue51
-rw-r--r--src/frontend/components/RepositoryNavbar.vue54
-rw-r--r--src/frontend/components/RepositoryTreeBlob.vue154
-rw-r--r--src/frontend/components/RepositoryTreeTree.vue84
-rw-r--r--src/frontend/router/index.js46
-rw-r--r--src/frontend/scss/abstracts/_colors.scss10
-rw-r--r--src/frontend/scss/abstracts/_fonts.scss5
-rw-r--r--src/frontend/scss/style.scss396
-rw-r--r--src/frontend/util/hljs-languages.js45
-rw-r--r--src/frontend/util/worker.js6
-rw-r--r--src/frontend/views/Home.vue62
-rw-r--r--src/frontend/views/Repository.vue29
-rw-r--r--src/frontend/views/RepositoryCommit.vue89
-rw-r--r--src/frontend/views/RepositoryLog.vue91
-rw-r--r--src/frontend/views/RepositoryTree.vue110
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