Compare commits

2 Commits

Author SHA1 Message Date
Julien Calixte
816c3687d8 fix(auth): clear stale credential error after github re-auth
The 401 flag and cached repo list were module-level and only reset
after a 20-min stale window, so re-authenticating left the
"credentials are invalid or expired" message pinned on. Watch the
access token: reset state and refetch on change. Also await
saveCredentials before redirecting so refs are settled.
2026-05-14 13:04:44 +02:00
Julien Calixte
f2f2a3114b style: no more underline for header tag 2026-05-14 01:22:46 +02:00
3 changed files with 68 additions and 51 deletions

View File

@@ -19,8 +19,7 @@ onBeforeMount(async () => {
if ("error" in token) { if ("error" in token) {
hasError.value = true hasError.value = true
} else { } else {
token.access_token await saveCredentials(token)
saveCredentials(token)
} }
router.replace({ name: "Home" }) router.replace({ name: "Home" })

View File

@@ -1,4 +1,4 @@
import { computed, ref } from "vue" import { computed, ref, watch } from "vue"
import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook" import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook"
import { RepoBase } from "@/modules/repo/interfaces/RepoBase" import { RepoBase } from "@/modules/repo/interfaces/RepoBase"
@@ -15,51 +15,70 @@ const currentPage = ref(0)
const totalCount = ref(0) const totalCount = ref(0)
let lastFetchedAt = 0 let lastFetchedAt = 0
export const useRepos = () => { const { username, accessToken } = useGitHubLogin()
const { username, accessToken } = useGitHubLogin()
const loadMore = async () => { const resetState = () => {
if (!accessToken.value || !username.value) { repos.value = []
isReady.value = true currentPage.value = 0
return totalCount.value = 0
} isReady.value = false
if (isLoading.value) return isLoading.value = false
isLoading.value = true hasCredentialError.value = false
try { lastFetchedAt = 0
const octokit = await getOctokit() }
const nextPage = currentPage.value + 1
const repoList = await octokit.request("GET /search/repositories", { const loadMore = async () => {
q: `user:${username.value}`, if (!accessToken.value || !username.value) {
per_page: PER_PAGE, isReady.value = true
page: nextPage return
})
currentPage.value = nextPage
totalCount.value = repoList.data.total_count
const newItems = repoList.data.items.map((item) => ({
id: `${item.id}`,
name: item.name,
isPrivate: item.private
}))
repos.value = [...repos.value, ...newItems].sort((a, b) =>
a.name < b.name ? -1 : 1
)
} catch (err: unknown) {
if (
typeof err === "object" &&
err !== null &&
"status" in err &&
(err as { status: number }).status === 401
) {
hasCredentialError.value = true
} else {
throw err
}
} finally {
isReady.value = true
isLoading.value = false
}
} }
if (isLoading.value) return
isLoading.value = true
try {
const octokit = await getOctokit()
const nextPage = currentPage.value + 1
const repoList = await octokit.request("GET /search/repositories", {
q: `user:${username.value}`,
per_page: PER_PAGE,
page: nextPage
})
currentPage.value = nextPage
totalCount.value = repoList.data.total_count
const newItems = repoList.data.items.map((item) => ({
id: `${item.id}`,
name: item.name,
isPrivate: item.private
}))
repos.value = [...repos.value, ...newItems].sort((a, b) =>
a.name < b.name ? -1 : 1
)
} catch (err: unknown) {
if (
typeof err === "object" &&
err !== null &&
"status" in err &&
(err as { status: number }).status === 401
) {
hasCredentialError.value = true
} else {
throw err
}
} finally {
isReady.value = true
isLoading.value = false
}
}
watch(accessToken, (next, prev) => {
if (next === prev) return
resetState()
if (next && username.value) {
lastFetchedAt = Date.now()
loadMore()
}
})
export const useRepos = () => {
const canLoadMore = computed( const canLoadMore = computed(
() => !isLoading.value && repos.value.length < totalCount.value () => !isLoading.value && repos.value.length < totalCount.value
) )
@@ -67,12 +86,7 @@ export const useRepos = () => {
const isStale = Date.now() - lastFetchedAt > STALE_TIME_MS const isStale = Date.now() - lastFetchedAt > STALE_TIME_MS
if (!isReady.value || isStale) { if (!isReady.value || isStale) {
if (isStale && isReady.value) { if (isStale && isReady.value) {
repos.value = [] resetState()
currentPage.value = 0
totalCount.value = 0
isReady.value = false
isLoading.value = false
hasCredentialError.value = false
} }
lastFetchedAt = Date.now() lastFetchedAt = Date.now()
loadMore() loadMore()

View File

@@ -109,6 +109,10 @@ a {
a.title-stacked-note-link { a.title-stacked-note-link {
display: block; display: block;
overflow: visible; overflow: visible;
&:hover {
cursor: pointer;
text-decoration: none;
}
} }
.title-stacked-note ul, .title-stacked-note ul,