Added repo tree to default virtual drive data

This commit is contained in:
Prozilla 2024-06-10 19:13:49 +02:00
parent 059c2e6835
commit 00b82c6548
No known key found for this signature in database
GPG key ID: 5858DFE71CAF31EE
7 changed files with 123 additions and 104 deletions

3
.gitignore vendored
View file

@ -24,4 +24,5 @@ yarn-debug.log*
yarn-error.log*
*.ini
/tmp
/tmp
/public/config/tree.json

View file

@ -15,7 +15,7 @@ echo -e "Commit message: \e[0;36m$COMMIT_MESSAGE\e[0m"
echo -e "Repository: \e[0;36m$REPO_URL\e[0m"
echo ""
if gh-pages -x -d dist -m $COMMIT_MESSAGE -r $REPO_URL ; then
if gh-pages -x -d dist -m "$COMMIT_MESSAGE" -r "$REPO_URL" ; then
echo -e "\e[0;32m✓ Successfully deployed to \e[0;36mhttps://$domain/\e[0m"
else
echo -e "\e[0;31mFailed to deploy\e[0m"

View file

@ -49,6 +49,12 @@ These are the scripts in logical order, that will be available when you have ins
> [!NOTE]
> After this deployment process, GitHub Pages will run its own build step to finalize the deployment, as seen in the `Actions` tab on GitHub. This usually takes less than a minute and once it's done, your deployment will be live.
### Other scripts
- `npm run fetch`
Fetch the repository tree using GitHub's API and store it as a JSON file that will be used to populate the virtual drive. More information can be found on the [virtual drive](./features/virtual-drive/README.md) page.
### Configuration
See [docs/configuration](configuration/README.md) for more information.

View file

@ -27,7 +27,7 @@ export function Example() {
The virtual root is a virtual folder that contains all other folders and files. It serves as the root directory for the virtual drive and is used as an access point in applications.
The default data for the virtual root is set in the `loadDefaultData()` function in the `VirtualRoot` class.
The default data for the virtual root is set in the `loadDefaultData()` function in the `VirtualRoot` class. It uses the contents of the GitHub repository to populate the root folder, allowing the user to browse the source code of ProzillaOS using its file explorer. To create or update the fetched repository tree data, so it can be used by ProzillaOS, run `npm run fetch`. This will fetch and cache the paths of every file and folder inside the repository. You should only run this command whenever a file/folder has been added/removed from the repo, because there is a [rate limit of 60 requests per hour](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api).
For more information about how the virtual root is stored and loaded, check the [Storage](../storage/README.md) docs.

View file

@ -12,7 +12,8 @@
"serve": "vite preview --port 8080 --host",
"predeploy": "npm run build && npm run stage",
"stage": "node --no-warnings --loader ts-node/esm ./src/tools/stage",
"deploy": "sh deploy.sh"
"deploy": "sh deploy.sh",
"fetch": "node --no-warnings --loader ts-node/esm ./src/tools/fetchRepository"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.0",

View file

@ -1,8 +1,8 @@
import { APPS } from "../../../config/apps.config";
import { WALLPAPERS } from "../../../config/desktop.config";
import AppsManager from "../../apps/appsManager";
import { VirtualFileLink } from "../file";
import { VirtualFolderLink } from "../folder";
import { VirtualFile, VirtualFileLink } from "../file";
import { VirtualFolder, VirtualFolderLink } from "../folder";
import { VirtualRoot } from "./virtualRoot";
/**
@ -22,7 +22,7 @@ export function loadDefaultData(virtualRoot: VirtualRoot) {
}).createFile("apps", "xml", (file) => {
file.setSource("/config/apps.xml");
}).createFile("theme", "xml", (file) => {
file.setSource("/config/apps.xml");
file.setSource("/config/theme.xml");
});
})
.createFolder("Pictures", (folder) => {
@ -79,107 +79,53 @@ export function loadDefaultData(virtualRoot: VirtualRoot) {
});
});
virtualRoot.createFolder(".github", (folder) => {
folder.createFile("FUNDING", "yml", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/.github/FUNDING.yml");
});
});
// Create files and folders based on repository tree
void fetch("/config/tree.json").then((response) =>
response.json()
).then(({ files, folders }: { files: string[], folders: string[] }) => {
virtualRoot.createFolder(".vscode", (folder) => {
folder.createFile("settings", "json", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/.vscode/settings.json");
});
});
folders.forEach((folderPath) => {
const lastSlashIndex = folderPath.lastIndexOf("/");
virtualRoot.createFolder("docs", (folder) => {
folder.createFile("README", "md", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/docs/README.md");
});
});
if (lastSlashIndex === -1) {
virtualRoot.createFolder(folderPath);
return;
}
virtualRoot.createFolder("public", (folder) => {
folder.createFolder("assets", (folder) => {
folder.createFolder("apps", (folder) => {
folder.createFolder("icons", (folder) => {
AppsManager.APPS.forEach(({ id }) => {
folder.createFile(id, "svg", (file) => {
file.setSource(AppsManager.getAppIconUrl(id));
});
});
});
}).createFolder("fonts", (folder) => {
folder.createFolders(["outfit", "roboto-mono"]);
}).createFolder("screenshots", (folder) => {
folder.createFile("screenshot", "png", (file) => {
file.setSource("/assets/screenshots/screenshot-files-info-taskbar-desktop.png");
});
}).createFolder("wallpapers", (folder) => {
folder.setProtected(true);
for (let i = 0; i < WALLPAPERS.length; i++) {
const source = WALLPAPERS[i];
const name = source.split("/").pop().split(".")[0];
folder.createFile(name, "png", (file) => {
file.setSource(source);
});
const parentPath = folderPath.substring(0, lastSlashIndex);
const folderName = folderPath.substring(lastSlashIndex + 1);
const parentFolder = virtualRoot.navigate(parentPath) as VirtualFolder;
parentFolder.createFolder(folderName);
});
files.forEach((filePath) => {
const lastSlashIndex = filePath.lastIndexOf("/");
const callback = (virtualFile: VirtualFile) => {
console.log(virtualFile.absolutePath);
const virtualPath = virtualFile.absolutePath;
if (virtualPath.startsWith("/public/")) {
virtualFile.setSource(virtualPath.replace(/^\/public\//, "/"));
} else {
virtualFile.setSource(`https://raw.githubusercontent.com/Prozilla/ProzillaOS/main${virtualPath}`);
}
}).createFile("banner", "png", (file) => {
file.setSource("/assets/banner-logo-title.png");
}).createFile("logo", "svg", (file) => {
file.setSource("/icon.svg");
});
}).createFolder("config", (folder) => {
folder.createFile("apps", "xml", (file) => {
file.setSource("/config/apps.xml");
}).createFile("desktop", "xml", (file) => {
file.setSource("/config/desktop.xml");
}).createFile("taskbar", "xml", (file) => {
file.setSource("/config/taskbar.xml");
}).createFile("theme", "xml", (file) => {
file.setSource("/config/theme.xml");
});
}).createFolder("documents", (folder) => {
folder.createFile("info", "md", (file) => {
file.setSource("/documents/info.md");
}).createFile("links", "md", (file) => {
file.setSource("/documents/links.md");
});
}).createFile("favicon", "ico", (file) => {
file.setSource("/favicon.ico");
}).createFile("index", "html", (file) => {
file.setSource("/index.html");
}).createFile("robots", "txt", (file) => {
file.setSource("/robots.txt");
}).createFile("sitemap", "xml", (file) => {
file.setSource("/sitemap.xml");
};
if (lastSlashIndex === -1) {
const { name, extension } = VirtualFile.convertId(filePath);
virtualRoot.createFile(name, extension, callback);
return;
}
const parentPath = filePath.substring(0, lastSlashIndex);
const { name, extension } = VirtualFile.convertId(filePath.substring(lastSlashIndex + 1));
const parentFolder = virtualRoot.navigate(parentPath) as VirtualFolder;
parentFolder.createFile(name, extension, callback);
});
});
virtualRoot.createFolder("src", (folder) => {
folder.createFolder("components")
.createFolder("config")
.createFolder("features")
.createFolder("hooks")
.createFolder("styles")
.createFile("App", "tsx", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/src/App.tsx");
}).createFile("index", "tsx", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/src/index");
});
});
virtualRoot.createFile("", "env", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/.env");
}).createFile("", "gitignore", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/.gitignore");
}).createFile("LICENSE", "md", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/LICENSE.md");
}).createFile("README", "md", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/README.md");
}).createFile("package", "json", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/package.json");
}).createFile("deploy", "sh", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/deploy.sh");
}).createFile("tsconfig", "json", (file) => {
file.setSource("https://raw.githubusercontent.com/Prozilla/ProzillaOS/main/tsconfig.json");
}).catch(() => {
console.warn("Failed to fetch repository tree. Make sure the tree data is valid and up-to-date using 'npm run fetch'.");
});
}

View file

@ -0,0 +1,65 @@
import fs from "node:fs";
import { ANSI } from "../config/apps/terminal.config";
const API_URL = "https://api.github.com/";
const TREE_PATH = "public/config/tree.json";
// TO DO: split these two variables into their own file
const OWNER = "Prozilla";
const REPO = "ProzillaOS";
const BRANCH = "main";
interface ReponseType {
sha: string;
url: string;
tree: {
path: string;
mode: string;
type: string;
sha: string;
url: string;
}[];
truncated: boolean;
}
function fetchRepositoryTree(callback: (tree: string) => void) {
const treeUrl = `${API_URL}repos/${OWNER}/${REPO}/git/trees/${BRANCH}?recursive=true`;
console.log(`${ANSI.fg.yellow}Fetching: ${ANSI.fg.cyan + treeUrl + ANSI.reset}`);
void fetch(treeUrl).then((response) =>
response.json()
).then((response: ReponseType) => {
const items = response.tree;
const files = [];
const folders = [];
items.forEach(({ path, type }) => {
if (type === "tree") {
folders.push(path);
} else {
files.push(path);
}
});
console.log(`Files found: ${ANSI.fg.cyan + files.length + ANSI.reset}`);
console.log(`Folders found: ${ANSI.fg.cyan + folders.length + ANSI.reset}`);
console.log(`Truncated: ${ANSI.fg.cyan + response.truncated.toString() + ANSI.reset}`);
const tree = JSON.stringify({ files, folders });
callback(tree);
}).catch((error) => {
console.error(error);
});
}
try {
fetchRepositoryTree((tree) => {
fs.writeFileSync(TREE_PATH, tree, { flag: "w+" });
console.log(`\n${ANSI.fg.green}✓ Generated repository tree: ${ANSI.fg.cyan + TREE_PATH + ANSI.reset}`);
});
} catch (error) {
console.error(error);
}