feat: improve caching of individual repositories
This commit adds the possibility to provide to the caching component data already known and to be cached immediately without the need of a callback function. This allows caching individual repositories without having to rely on additional API calls. However, repos can also be retrieved individually from the GitHub API based on their full name.
This commit is contained in:
parent
e0bcdb6dd3
commit
1678100198
@ -1,5 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<Cache name="repos" :callback="fetchData" @cached="processCachedData" />
|
<Cache
|
||||||
|
:name="props.cacheName"
|
||||||
|
:callback="fetchData"
|
||||||
|
:data="alreadyKnownData"
|
||||||
|
@cached="processCachedData"
|
||||||
|
/>
|
||||||
<slot v-if="loading" name="loader">
|
<slot v-if="loading" name="loader">
|
||||||
<Loader />
|
<Loader />
|
||||||
</slot>
|
</slot>
|
||||||
@ -23,6 +28,11 @@ const props = defineProps({
|
|||||||
required: true,
|
required: true,
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
cacheName: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
alreadyKnownData: Object,
|
||||||
});
|
});
|
||||||
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
|
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ const props = defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
|
data: {
|
||||||
|
default: null,
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['cached']);
|
const emits = defineEmits(['cached']);
|
||||||
@ -29,25 +33,31 @@ const isDataOutdated = (name: string): boolean => {
|
|||||||
return elapsedTime > props.lifetime;
|
return elapsedTime > props.lifetime;
|
||||||
};
|
};
|
||||||
|
|
||||||
const storeInCache = (data: Observable<any>, name: string): Observable<any> => {
|
const storeInCache = (
|
||||||
data.subscribe({
|
callback: Function,
|
||||||
|
data: any,
|
||||||
|
name: string
|
||||||
|
): Observable<any> => {
|
||||||
|
let response: Observable<any> = data ? of(data) : callback();
|
||||||
|
|
||||||
|
response.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
localStorage.setItem(name, JSON.stringify(response));
|
localStorage.setItem(name, JSON.stringify(response));
|
||||||
localStorage.setItem(name + '-timestamp', `${Date.now()}`);
|
localStorage.setItem(name + '-timestamp', `${Date.now()}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return data;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDataOutdated(props.name)) {
|
if (isDataOutdated(props.name)) {
|
||||||
emits('cached', storeInCache(props.callback(), props.name));
|
emits('cached', storeInCache(props.callback, props.data, props.name));
|
||||||
} else {
|
} else {
|
||||||
let data = localStorage.getItem(props.name);
|
let data = localStorage.getItem(props.name);
|
||||||
try {
|
try {
|
||||||
emits('cached', of(JSON.parse(data)));
|
emits('cached', of(JSON.parse(data)));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Could not parse data found in cache: ${err}`);
|
console.error(`Could not parse data found in cache: ${err}`);
|
||||||
emits('cached', storeInCache(props.callback(), props.name));
|
emits('cached', storeInCache(props.callback, props.data, props.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,26 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="githubRepo flex-row flex-space-between gap-1rem rounded-corners">
|
<div class="githubRepo flex-row flex-space-between gap-1rem rounded-corners">
|
||||||
|
<ApiLoader
|
||||||
|
:cache-name="repoName()"
|
||||||
|
:url="fetchUrl"
|
||||||
|
:already-known-data="props.data"
|
||||||
|
@data-loaded="(repo: GithubRepo) => (repository = repo)"
|
||||||
|
>
|
||||||
<div class="flex-col info">
|
<div class="flex-col info">
|
||||||
<h3>{{ props.repo.name }}</h3>
|
<h3>{{ props.data.name }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{{ props.repo.description }}
|
{{ props.data.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-col flex-start gap-1rem stats">
|
<div class="flex-col flex-start gap-1rem stats">
|
||||||
<p>Stars: {{ repo.stargazers_count }}</p>
|
<p>Stars: {{ data.stargazers_count }}</p>
|
||||||
<p>Forks: {{ repo.forks_count }}</p>
|
<p>Forks: {{ data.forks_count }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</ApiLoader>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import ApiLoader from '../ApiLoader.vue';
|
||||||
|
|
||||||
import { GithubRepo } from '../../composables/github';
|
import { GithubRepo } from '../../composables/github';
|
||||||
import { PropType } from 'vue';
|
import { PropType, Ref, ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
repo: Object as PropType<GithubRepo>,
|
data: Object as PropType<GithubRepo>,
|
||||||
|
repoName: String,
|
||||||
|
fetcher: String as PropType<'gitea' | 'github'>,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const repoName = (): string => {
|
||||||
|
return props.data ? props.data.full_name : props.repoName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchUrl = `https://api.github.com/repos/${repoName()}`;
|
||||||
|
const repository: Ref<GithubRepo> = ref(null);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-col gap-1rem list-repos">
|
<div class="flex-col gap-1rem list-repos">
|
||||||
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos">
|
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos">
|
||||||
<GithubRepository
|
<GithubRepository
|
||||||
:repo="repo"
|
:data="repo"
|
||||||
type="repositories"
|
type="repositories"
|
||||||
v-for="repo in repos"
|
v-for="repo in repos"
|
||||||
class="center"
|
class="center"
|
||||||
|
Loading…
Reference in New Issue
Block a user