diff --git a/packages/core/src/actions/entries.ts b/packages/core/src/actions/entries.ts index 86da780a..2089d8f9 100644 --- a/packages/core/src/actions/entries.ts +++ b/packages/core/src/actions/entries.ts @@ -635,8 +635,8 @@ export function loadEntry(collection: CollectionWithDefaults, slug: string, sile try { await dispatch(loadMedia()); const loadedEntry = await tryLoadEntry(getState(), collection, slug); - dispatch(entryLoaded(collection, loadedEntry)); dispatch(createDraftFromEntry(collection, loadedEntry)); + dispatch(entryLoaded(collection, loadedEntry)); } catch (error: unknown) { console.error(error); if (error instanceof Error) { @@ -668,7 +668,7 @@ export async function tryLoadEntry( } const backend = currentBackend(configState.config); - return backend.getEntry(state, collection, configState.config, slug); + return await backend.getEntry(state, collection, configState.config, slug); } interface AppendAction { diff --git a/packages/core/src/backends/git/implementation.tsx b/packages/core/src/backends/git/implementation.tsx index b8683b97..4c957f2e 100644 --- a/packages/core/src/backends/git/implementation.tsx +++ b/packages/core/src/backends/git/implementation.tsx @@ -2,25 +2,28 @@ import FS from '@isomorphic-git/lightning-fs'; import * as git from 'isomorphic-git'; import http from 'isomorphic-git/http/web'; -import type { WorkflowStatus } from '@staticcms/core/constants/publishModes'; -import type { AssetProxy } from '@staticcms/core/valueObjects'; -import type { - Backend, - BackendClass, - BackendEntry, - Config, - ConfigWithDefaults, - Credentials, - Cursor, - DisplayURL, - ImplementationEntry, - ImplementationFile, - PersistOptions, - User, +import { + asyncLock, + runWithLock, + type AsyncLock, + type Backend, + type BackendClass, + type BackendEntry, + type Config, + type ConfigWithDefaults, + type Credentials, + type Cursor, + type DisplayURL, + type ImplementationEntry, + type ImplementationFile, + type PersistOptions, + type User, } from '@staticcms/core'; +import type { WorkflowStatus } from '@staticcms/core/constants/publishModes'; +import type { AssetProxy } from '@staticcms/core/valueObjects'; + const dir = '/repo'; -let singleton: Promise; function determineRepositoryURL(backend: Backend): string { const name = backend.name; @@ -50,7 +53,8 @@ export default function GitProxyBackEndGenerator( fs: FS; pfs: FS.PromisifiedFS; repositoryUrl: string; - repository: Promise; + lock: AsyncLock; + sha: string; constructor(config: ConfigWithDefaults, options = {}) { this.backend = new T(config, options); @@ -58,48 +62,63 @@ export default function GitProxyBackEndGenerator( this.fs = new FS('decapfs'); this.pfs = this.fs.promises; this.repositoryUrl = determineRepositoryURL(config.backend); - if (!singleton) { - singleton = this.getRepository(); - } - this.repository = singleton; + this.lock = asyncLock(); + this.sha = ''; } async getRepository() { - const branch = this.config.backend.branch || 'main'; - try { - await this.pfs.stat(dir); - } catch (e) { - await this.pfs.mkdir(dir); - await git.init({ - fs: this.fs, - dir, - defaultBranch: branch, - }); - } - await git.addRemote({ - fs: this.fs, - dir, - url: this.repositoryUrl, - remote: 'origin', - force: true, - }); - await git.fetch({ - fs: this.fs, - http, - dir, - remote: 'origin', - ref: branch, - singleBranch: true, - depth: 1, - }); - await git.checkout({ - fs: this.fs, - dir, - ref: branch, - force: true, - track: false, - }); - return this.pfs.readdir(dir); + return await runWithLock( + this.lock, + async () => { + const branch = this.config.backend.branch || 'main'; + try { + await this.pfs.stat(dir); + } catch (e) { + await this.pfs.mkdir(dir); + await git.init({ + fs: this.fs, + dir, + defaultBranch: branch, + }); + } + await git.addRemote({ + fs: this.fs, + dir, + url: this.repositoryUrl, + remote: 'origin', + force: true, + }); + console.log('Fetching repo...'); + await git.fetch({ + fs: this.fs, + http, + dir, + remote: 'origin', + ref: branch, + singleBranch: true, + depth: 1, + onMessage: message => console.log(message), + }); + const newSHA = await git.resolveRef({ fs: this.fs, dir, ref: `origin/${branch}` }); + console.log(`Current SHA: ${this.sha}, new SHA: ${newSHA}`); + if (this.sha !== newSHA) { + console.log('Run checkout...'); + await git.checkout({ + fs: this.fs, + dir, + ref: `origin/${branch}`, + noUpdateHead: false, + force: true, + track: false, + onPostCheckout: post => { + this.sha = post.newHead; + console.log(`New HEAD: ${post.newHead}`); + }, + }); + } + }, + 'Failed to get async lock', + ); } isGitBackend() { @@ -108,7 +127,7 @@ export default function GitProxyBackEndGenerator( async entriesByFolder(folder: string, extension: string) { try { - await this.repository; + await this.getRepository(); const files = await this.pfs.readdir(`${dir}/${folder}`); const relevantFiles = files.filter((name: string) => name.endsWith(extension)); return Promise.all( @@ -130,7 +149,7 @@ export default function GitProxyBackEndGenerator( } } async getEntry(path: string) { - await this.repository; + await this.getRepository(); let data = await this.pfs.readFile(`${dir}/${path}`, 'utf8'); if (data instanceof Uint8Array) { data = new TextDecoder().decode(data); diff --git a/packages/core/src/components/media-library/common/MediaLibraryCard.tsx b/packages/core/src/components/media-library/common/MediaLibraryCard.tsx index 9841c637..c8f5dc69 100644 --- a/packages/core/src/components/media-library/common/MediaLibraryCard.tsx +++ b/packages/core/src/components/media-library/common/MediaLibraryCard.tsx @@ -105,10 +105,10 @@ const MediaLibraryCard: FC = ({ }, [displayURL.url, text]); useEffect(() => { - if (!displayURL.url) { + if (!isDirectory && !displayURL.url) { loadDisplayURL(); } - }, [displayURL.url, loadDisplayURL]); + }, [displayURL.url, loadDisplayURL, isDirectory]); const shortenedText = useMemo( () =>