Skip to content

Commit

Permalink
move AtlasManager to a Vue plugin
Browse files Browse the repository at this point in the history
and make the local storage persistent
  • Loading branch information
mirkobrombin committed Aug 5, 2023
1 parent 6e2962a commit 1133223
Show file tree
Hide file tree
Showing 10 changed files with 582 additions and 1,964 deletions.
2,127 changes: 367 additions & 1,760 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
{
"name": "image-registry",
"version": "0.0.0",
"name": "atlas",
"private": true,
"version": "2.0.0",
"scripts": {
"dev": "vite",
"build": "run-p type-check build-only",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
Expand All @@ -15,19 +14,19 @@
"highlight.js": "^11.8.0",
"js-yaml": "^4.1.0",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.2.47",
"vue-highlightjs": "^1.3.3",
"vue-router": "^4.1.6",
"vuetify": "^3.3.11"
"vue-router": "^4.2.2"
},
"devDependencies": {
"@types/js-yaml": "^4.0.5",
"@types/node": "^18.17.1",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"npm-run-all": "^4.1.5",
"typescript": "~4.8.4",
"typescript": "^5.0.2",
"vite": "^4.4.7",
"vue-tsc": "^1.2.0"
"vue-tsc": "^1.4.2"
}
}
8 changes: 8 additions & 0 deletions src/core/loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { App } from "vue";
import AtlasManager from "@/core/manager";

export default {
install(app: App) {
app.use(AtlasManager)
},
};
257 changes: 139 additions & 118 deletions src/core/manager.ts
Original file line number Diff line number Diff line change
@@ -1,144 +1,165 @@
import type { App } from "vue";
import axios from "axios";
import * as yaml from "js-yaml";
import type { VibRecipe, Module } from "@/core/models";
import AtlasConfig from "@/config";
import { useAtlasStore } from '@/core/store';

class AtlasManager {
private static readonly storageKey = "vibRecipes";

private static async fetchRecipeFromRepo(
repo: string
): Promise<string | null> {
const url = `${AtlasConfig.registry}/${repo}/main/recipe.yml`;
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(
`Error fetching recipe.yml from ${repo}: ${(error as Error).message}`
);
return null;
}
}
import { useAtlasStore } from "@/core/store";


private static async fetchModuleContentFromRepo(
export interface IAtlasManager {
getVibRecipes(force: boolean): Promise<VibRecipe[]>;
getVibRecipe(id: string): Promise<VibRecipe | null>;
getFetchDate(): Promise<Date | null>;
fetchRecipeFromRepo(repo: string): Promise<string | null>;
fetchModuleContentFromRepo(
repo: string,
path: string
): Promise<string | null> {
const url = `${AtlasConfig.registry}/${repo}/main/${path}.yml`;
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(
`Error fetching module content from ${url}: ${(error as Error).message}`
);
return null;
}
}
): Promise<string | null>;
}

private static getFromLocalStorage(): VibRecipe[] | null {
export default {
install: (app: App) => {
const store = useAtlasStore();
return store.getVibRecipes;
}

private static saveToLocalStorage(recipes: VibRecipe[]): void {
const store = useAtlasStore();
store.setVibRecipes(recipes);
}
app.config.globalProperties.$atlasManager = {
async getVibRecipes(force: boolean = false): Promise<VibRecipe[]> {
console.log("Fetching VibRecipes...");

if (!force) {
console.log("Checking for cached VibRecipes...");
const cachedRecipes = store.vibRecipes;
const lastFetchDate = store.lastFetchDate;

if (cachedRecipes.length > 0 && lastFetchDate) {
console.log("Using cached VibRecipes.");
return cachedRecipes;
}
} else {
console.log("Forcing fetch of VibRecipes...");
}

public static async getVibRecipes(force: boolean = false): Promise<VibRecipe[]> {
console.log("Fetching VibRecipes...");

if (!force) {
const cachedRecipes = this.getFromLocalStorage();
const lastFetchDate = localStorage.getItem("lastFetchDate");

if (cachedRecipes !== null && cachedRecipes.length > 0 && lastFetchDate) {
console.log("Using cached VibRecipes.");
return cachedRecipes;
}
}

const vibRecipes: VibRecipe[] = [];

try {
const fetchPromises = AtlasConfig.repos.map(async (repo) => {
console.log(`Fetching recipe.yml from ${repo}`);
const recipeYaml = await this.fetchRecipeFromRepo(repo);
if (recipeYaml !== null) {
console.log(`Parsing recipe.yml from ${repo}`);
const recipeObject = yaml.load(recipeYaml) as VibRecipe;
recipeObject.snippet = recipeYaml;
const modules: Module[] = [];

if (recipeObject.modules) {
for (const module of recipeObject.modules) {
if (module.includes) {
console.log(
`Fetching and processing included modules for ${repo}`
);
for (const includePath of module.includes) {
const moduleContent = await this.fetchModuleContentFromRepo(
repo,
includePath
);
if (moduleContent) {
try {
const includedModule = yaml.load(moduleContent) as Module;
includedModule.snippet = moduleContent;
modules.push(includedModule);
} catch (error) {
console.error(
`Error parsing included module from ${repo}: ${(error as Error).message
}`
const vibRecipes: VibRecipe[] = [];

try {
const fetchPromises = AtlasConfig.repos.map(async (repo) => {
console.log(`Fetching recipe.yml from ${repo}`);
const recipeYaml = await this.fetchRecipeFromRepo(repo);
if (recipeYaml !== null) {
console.log(`Parsing recipe.yml from ${repo}`);
const recipeObject = yaml.load(recipeYaml) as VibRecipe;
recipeObject.snippet = recipeYaml;
const modules: Module[] = [];

if (recipeObject.modules) {
for (const module of recipeObject.modules) {
if (module.includes) {
console.log(
`Fetching and processing included modules for ${repo}`
);
for (const includePath of module.includes) {
const moduleContent = await this.fetchModuleContentFromRepo(
repo,
includePath
);
if (moduleContent) {
try {
const includedModule = yaml.load(
moduleContent
) as Module;
includedModule.snippet = moduleContent;
modules.push(includedModule);
} catch (error) {
console.error(
`Error parsing included module from ${repo}: ${(error as Error).message}`
);
}
}
}
} else {
module.snippet = yaml.dump(module);
modules.push(module);
}
}
} else {
module.snippet = yaml.dump(module);
modules.push(module);
}

recipeObject.id = repo.replace("/", "-");
recipeObject.modules = modules;
vibRecipes.push(recipeObject);
}
}
});

recipeObject.id = repo.replace("/", "-");
recipeObject.modules = modules;
vibRecipes.push(recipeObject);
await Promise.all(fetchPromises);
} catch (error) {
console.error(
`Error fetching or parsing recipes: ${(error as Error).message}`
);
}
});

await Promise.all(fetchPromises);
} catch (error) {
console.error(`Error fetching or parsing recipes: ${(error as Error).message}`);
}
store.$patch({ vibRecipes: vibRecipes });
store.$patch({ lastFetchDate: Date.now() });

this.saveToLocalStorage(vibRecipes);
console.log("Finished fetching VibRecipes");
return vibRecipes;
},

console.log("Finished fetching VibRecipes");
return vibRecipes;
}
async getVibRecipe(id: string): Promise<VibRecipe | null> {
const vibRecipes = await this.getVibRecipes(false);
for (const recipe of vibRecipes) {
if (recipe.id === id) {
return recipe;
}
}
return null;
},

public static async getVibRecipe(id: string): Promise<VibRecipe | null> {
const vibRecipes = await this.getVibRecipes();
for (const recipe of vibRecipes) {
if (recipe.id === id) {
return recipe;
}
}
return null;
}
async getFetchDate(): Promise<Date | null> {
const lastFetchDate = store.lastFetchDate;
if (lastFetchDate) {
return new Date(lastFetchDate);
}
return null;
},

async fetchRecipeFromRepo(repo: string): Promise<string | null> {
const url = `${AtlasConfig.registry}/${repo}/main/recipe.yml`;
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(
`Error fetching recipe.yml from ${repo}: ${(error as Error).message}`
);
return null;
}
},

async fetchModuleContentFromRepo(
repo: string,
path: string
): Promise<string | null> {
const url = `${AtlasConfig.registry}/${repo}/main/${path}.yml`;
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(
`Error fetching module content from ${url}: ${(error as Error).message}`
);
return null;
}
},
} as IAtlasManager;

public static getFetchDate(): Date | null {
const store = useAtlasStore();
const lastFetchDate = store.getLastFetchDate;
if (lastFetchDate) {
return new Date(lastFetchDate);
}
return null;
console.log("AtlasManager: fetching VibRecipes...");
app.config.globalProperties.$atlasManager.getVibRecipes(false);
console.log("AtlasManager: done");

},
};

declare module "@vue/runtime-core" {
//Bind to `this` keyword
interface IAtlasManager {
$atlasManager: IAtlasManager;
}
}

export default AtlasManager;
35 changes: 5 additions & 30 deletions src/core/store.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
import { defineStore } from 'pinia';
import type { VibRecipe } from '@/core/models';

export const useAtlasStore = defineStore({
id: 'atlas',
export const useAtlasStore = defineStore('atlas', {
state: () => ({
vibRecipes: null as VibRecipe[] | null,
lastFetchDate: null as string | null,
vibRecipes: [] as VibRecipe[],
lastFetchDate: Date.now(),
}),
getters: {
getVibRecipes(): VibRecipe[] {
if (this.vibRecipes) {
return this.vibRecipes;
}

const vibRecipes = localStorage.getItem("vibRecipes");
if (vibRecipes) {
this.vibRecipes = JSON.parse(vibRecipes) as VibRecipe[];
this.lastFetchDate = localStorage.getItem("lastFetchDate");
return this.vibRecipes;
}

return [];
},
getLastFetchDate(): string | null {
return this.lastFetchDate;
},
},
actions: {
setVibRecipes(vibRecipes: VibRecipe[]) {
this.vibRecipes = vibRecipes;
this.lastFetchDate = new Date().toISOString();
localStorage.setItem("vibRecipes", JSON.stringify(vibRecipes));
localStorage.setItem("lastFetchDate", this.lastFetchDate);
},
persist: {
storage: window.localStorage,
},
});
Loading

0 comments on commit 1133223

Please sign in to comment.