Feat: nested collections (#3716)

This commit is contained in:
Erez Rokah
2020-06-18 10:11:37 +03:00
committed by GitHub
parent b4c47caf59
commit af7bbbd9a9
89 changed files with 8269 additions and 5619 deletions

View File

@ -26,13 +26,16 @@ export interface UnpublishedEntryMediaFile {
}
export interface ImplementationEntry {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: string;
file: { path: string; label?: string; id?: string | null; author?: string; updatedOn?: string };
slug?: string;
mediaFiles?: ImplementationMediaFile[];
metaData?: { collection: string; status: string };
isModification?: boolean;
}
export interface UnpublishedEntry {
slug: string;
collection: string;
status: string;
diffs: { id: string; path: string; newFile: boolean }[];
updatedAt: string;
}
export interface Map {
@ -48,7 +51,7 @@ export type AssetProxy = {
toBase64?: () => Promise<string>;
};
export type Entry = { path: string; slug: string; raw: string };
export type Entry = { path: string; slug: string; raw: string; newPath?: string };
export type PersistOptions = {
newEntry?: boolean;
@ -116,8 +119,24 @@ export interface Implementation {
persistMedia: (file: AssetProxy, opts: PersistOptions) => Promise<ImplementationMediaFile>;
deleteFile: (path: string, commitMessage: string) => Promise<void>;
unpublishedEntries: () => Promise<ImplementationEntry[]>;
unpublishedEntry: (collection: string, slug: string) => Promise<ImplementationEntry>;
unpublishedEntries: () => Promise<string[]>;
unpublishedEntry: (args: {
id?: string;
collection?: string;
slug?: string;
}) => Promise<UnpublishedEntry>;
unpublishedEntryDataFile: (
collection: string,
slug: string,
path: string,
id: string,
) => Promise<string>;
unpublishedEntryMediaFile: (
collection: string,
slug: string,
path: string,
id: string,
) => Promise<ImplementationMediaFile>;
updateUnpublishedEntryStatus: (
collection: string,
slug: string,
@ -155,12 +174,6 @@ export type ImplementationFile = {
path: string;
};
type Metadata = {
objects: { entry: { path: string } };
collection: string;
status: string;
};
type ReadFile = (
path: string,
id: string | null | undefined,
@ -169,10 +182,6 @@ type ReadFile = (
type ReadFileMetadata = (path: string, id: string | null | undefined) => Promise<FileMetadata>;
type ReadUnpublishedFile = (
key: string,
) => Promise<{ metaData: Metadata; fileData: string; isModification: boolean; slug: string }>;
const fetchFiles = async (
files: ImplementationFile[],
readFile: ReadFile,
@ -206,47 +215,6 @@ const fetchFiles = async (
) as Promise<ImplementationEntry[]>;
};
const fetchUnpublishedFiles = async (
keys: string[],
readUnpublishedFile: ReadUnpublishedFile,
apiName: string,
) => {
const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
const promises = [] as Promise<ImplementationEntry | { error: boolean }>[];
keys.forEach(key => {
promises.push(
new Promise(resolve =>
sem.take(() =>
readUnpublishedFile(key)
.then(data => {
if (data === null || data === undefined) {
resolve({ error: true });
sem.leave();
} else {
resolve({
slug: data.slug,
file: { path: data.metaData.objects.entry.path, id: null },
data: data.fileData,
metaData: data.metaData,
isModification: data.isModification,
});
sem.leave();
}
})
.catch((error = true) => {
sem.leave();
console.error(`failed to load file from ${apiName}: ${key}`);
resolve({ error });
}),
),
),
);
});
return Promise.all(promises).then(loadedEntries =>
loadedEntries.filter(loadedEntry => !(loadedEntry as { error: boolean }).error),
) as Promise<ImplementationEntry[]>;
};
export const entriesByFolder = async (
listFiles: () => Promise<ImplementationFile[]>,
readFile: ReadFile,
@ -266,15 +234,10 @@ export const entriesByFiles = async (
return fetchFiles(files, readFile, readFileMetadata, apiName);
};
export const unpublishedEntries = async (
listEntriesKeys: () => Promise<string[]>,
readUnpublishedFile: ReadUnpublishedFile,
apiName: string,
) => {
export const unpublishedEntries = async (listEntriesKeys: () => Promise<string[]>) => {
try {
const keys = await listEntriesKeys();
const entries = await fetchUnpublishedFiles(keys, readUnpublishedFile, apiName);
return entries;
return keys;
} catch (error) {
if (error.message === 'Not Found') {
return Promise.resolve([]);
@ -392,7 +355,6 @@ type GetDiffFromLocalTreeMethods = {
oldPath: string;
newPath: string;
status: string;
binary: boolean;
}[]
>;
filterFile: (file: { path: string; name: string }) => boolean;
@ -417,7 +379,7 @@ const getDiffFromLocalTree = async ({
}: GetDiffFromLocalTreeArgs) => {
const diff = await getDifferences(branch.sha, localTree.head);
const diffFiles = diff
.filter(d => (d.oldPath?.startsWith(folder) || d.newPath?.startsWith(folder)) && !d.binary)
.filter(d => d.oldPath?.startsWith(folder) || d.newPath?.startsWith(folder))
.reduce((acc, d) => {
if (d.status === 'renamed') {
acc.push({

View File

@ -20,6 +20,7 @@ import { asyncLock, AsyncLock as AL } from './asyncLock';
import {
Implementation as I,
ImplementationEntry as IE,
UnpublishedEntry as UE,
ImplementationMediaFile as IMF,
ImplementationFile as IF,
DisplayURLObject as DUO,
@ -75,6 +76,7 @@ import {
export type AsyncLock = AL;
export type Implementation = I;
export type ImplementationEntry = IE;
export type UnpublishedEntry = UE;
export type ImplementationMediaFile = IMF;
export type ImplementationFile = IF;
export type DisplayURL = DU;