refactor(github-content): expose conflict info and add latest-sha lookup
updateFile/createFile now return { sha, conflict } so 409/422 from GitHub
can drive a UI flow instead of being swallowed as a generic save error.
Also adds fetchLatestSha(path) for cheap freshness checks against HEAD.
This commit is contained in:
@@ -74,7 +74,7 @@ export const useCheckboxCommit = ({
|
|||||||
|
|
||||||
isCommitting.value = true
|
isCommitting.value = true
|
||||||
|
|
||||||
const newSha = await updateFile({
|
const { sha: newSha } = await updateFile({
|
||||||
content: pendingContent.value,
|
content: pendingContent.value,
|
||||||
path: pathValue,
|
path: pathValue,
|
||||||
sha: currentSha.value
|
sha: currentSha.value
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { getOctokit } from "@/modules/repo/services/octo"
|
|||||||
import { encodeUTF8ToBase64 } from "@/utils/decodeBase64ToUTF8"
|
import { encodeUTF8ToBase64 } from "@/utils/decodeBase64ToUTF8"
|
||||||
import { confirmMessage, errorMessage } from "@/utils/notif"
|
import { confirmMessage, errorMessage } from "@/utils/notif"
|
||||||
|
|
||||||
|
const isConflictStatus = (status: number) => status === 409 || status === 422
|
||||||
|
|
||||||
export const useGitHubContent = ({
|
export const useGitHubContent = ({
|
||||||
user,
|
user,
|
||||||
repo
|
repo
|
||||||
@@ -9,6 +11,21 @@ export const useGitHubContent = ({
|
|||||||
user: string
|
user: string
|
||||||
repo: string
|
repo: string
|
||||||
}) => {
|
}) => {
|
||||||
|
const fetchLatestSha = async (path: string): Promise<string | null> => {
|
||||||
|
try {
|
||||||
|
const octokit = await getOctokit()
|
||||||
|
const response = await octokit.request(
|
||||||
|
"GET /repos/{owner}/{repo}/contents/{path}",
|
||||||
|
{ owner: user, repo, path }
|
||||||
|
)
|
||||||
|
const data = response?.data
|
||||||
|
if (Array.isArray(data) || !data) return null
|
||||||
|
return "sha" in data ? data.sha : null
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const putFile = async ({
|
const putFile = async ({
|
||||||
content,
|
content,
|
||||||
path,
|
path,
|
||||||
@@ -17,7 +34,7 @@ export const useGitHubContent = ({
|
|||||||
content: string
|
content: string
|
||||||
path: string
|
path: string
|
||||||
sha?: string
|
sha?: string
|
||||||
}) => {
|
}): Promise<{ sha: string | null; conflict: boolean }> => {
|
||||||
try {
|
try {
|
||||||
const octokit = await getOctokit()
|
const octokit = await getOctokit()
|
||||||
|
|
||||||
@@ -35,18 +52,27 @@ export const useGitHubContent = ({
|
|||||||
|
|
||||||
confirmMessage("✅ Note saved")
|
confirmMessage("✅ Note saved")
|
||||||
|
|
||||||
return response?.data.content?.sha ?? null
|
return { sha: response?.data.content?.sha ?? null, conflict: false }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const status = (error as { status?: number })?.status
|
||||||
|
if (status && isConflictStatus(status)) {
|
||||||
|
errorMessage("⚠ Conflict: this note changed on GitHub")
|
||||||
|
console.warn(error)
|
||||||
|
return { sha: null, conflict: true }
|
||||||
|
}
|
||||||
errorMessage("❌ Note could not be saved")
|
errorMessage("❌ Note could not be saved")
|
||||||
console.warn(error)
|
console.warn(error)
|
||||||
|
return { sha: null, conflict: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updateFile: async (props: { content: string; path: string; sha: string }) =>
|
fetchLatestSha,
|
||||||
putFile(props),
|
updateFile: async (props: {
|
||||||
|
content: string
|
||||||
|
path: string
|
||||||
|
sha: string
|
||||||
|
}) => putFile(props),
|
||||||
createFile: async (props: { content: string; path: string }) =>
|
createFile: async (props: { content: string; path: string }) =>
|
||||||
putFile(props)
|
putFile(props)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ watch(mode, async (newMode) => {
|
|||||||
newContent.value
|
newContent.value
|
||||||
}`
|
}`
|
||||||
|
|
||||||
const newSha = await createFile({
|
const { sha: newSha } = await createFile({
|
||||||
content,
|
content,
|
||||||
path: newContentPath
|
path: newContentPath
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user