Added website config collection
This commit is contained in:
parent
af7c5ee5a0
commit
39e2642c55
|
@ -13,7 +13,7 @@
|
||||||
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/ && copyfiles -u 1 \"src/sdk.ts\" dist/ && copyfiles -u 1 \"src/constants.ts\" dist/ && copyfiles -u 1 \"src/types/collections.ts\" dist/",
|
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/ && copyfiles -u 1 \"src/sdk.ts\" dist/ && copyfiles -u 1 \"src/constants.ts\" dist/ && copyfiles -u 1 \"src/types/collections.ts\" dist/",
|
||||||
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
|
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
|
||||||
"generate:graphQLSchema": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema",
|
"generate:graphQLSchema": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema",
|
||||||
"unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport='src/payload.config.ts;src/sdk.ts;src/types/collections.ts'",
|
"unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport='src/payload.config.ts;src/constants.ts;src/sdk.ts;src/types/collections.ts'",
|
||||||
"prettier": "prettier --list-different --end-of-line auto --write src",
|
"prettier": "prettier --list-different --end-of-line auto --write src",
|
||||||
"tsc": "tsc --noEmit",
|
"tsc": "tsc --noEmit",
|
||||||
"precommit": "npm run generate:types && npm run prettier && npm run unused-exports && npm run tsc",
|
"precommit": "npm run generate:types && npm run prettier && npm run unused-exports && npm run tsc",
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { RecordersRoles } from "../../constants";
|
|
||||||
import { Recorder } from "../../types/collections";
|
|
||||||
import { EndpointAccess } from "../../types/payload";
|
|
||||||
import { isDefined, isUndefined } from "../../utils/asserts";
|
|
||||||
|
|
||||||
export const mustBeAdmin: EndpointAccess<Recorder> = ({ user }) => {
|
|
||||||
if (isUndefined(user)) return false;
|
|
||||||
return isDefined(user.role) && user.role.includes(RecordersRoles.Admin);
|
|
||||||
};
|
|
|
@ -1,46 +0,0 @@
|
||||||
import { GlobalConfig } from "payload/types";
|
|
||||||
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
|
|
||||||
import { CollectionGroups, Collections } from "../../constants";
|
|
||||||
import { imageField } from "../../fields/imageField/imageField";
|
|
||||||
import { rowField } from "../../fields/rowField/rowField";
|
|
||||||
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
|
|
||||||
|
|
||||||
const fields = {
|
|
||||||
folders: "folders",
|
|
||||||
darkThumbnail: "darkThumbnail",
|
|
||||||
lightThumbnail: "lightThumbnail",
|
|
||||||
folder: "folder",
|
|
||||||
icon: "icon",
|
|
||||||
} as const satisfies Record<string, string>;
|
|
||||||
|
|
||||||
export const HomeFolders: GlobalConfig = {
|
|
||||||
slug: Collections.HomeFolders,
|
|
||||||
typescript: { interface: "HomeFolder" },
|
|
||||||
admin: {
|
|
||||||
group: CollectionGroups.Meta,
|
|
||||||
},
|
|
||||||
access: { update: mustBeAdmin },
|
|
||||||
endpoints: [getAllEndpoint],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: fields.folders,
|
|
||||||
admin: {
|
|
||||||
description:
|
|
||||||
"These will be the folders displayed on the home page, under the Library section.",
|
|
||||||
},
|
|
||||||
type: "array",
|
|
||||||
fields: [
|
|
||||||
rowField([
|
|
||||||
imageField({ name: fields.lightThumbnail, relationTo: Collections.Images }),
|
|
||||||
imageField({ name: fields.darkThumbnail, relationTo: Collections.Images }),
|
|
||||||
{
|
|
||||||
name: fields.folder,
|
|
||||||
type: "relationship",
|
|
||||||
relationTo: Collections.Folders,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
|
@ -1,47 +0,0 @@
|
||||||
import payload from "payload";
|
|
||||||
import { Collections } from "../../../constants";
|
|
||||||
import { EndpointHomeFolder } from "../../../sdk";
|
|
||||||
import { Folder } from "../../../types/collections";
|
|
||||||
import { CollectionEndpoint } from "../../../types/payload";
|
|
||||||
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
|
|
||||||
import { convertFolderToPreview } from "../../Folders/endpoints/getBySlugEndpoint";
|
|
||||||
|
|
||||||
export const getAllEndpoint: CollectionEndpoint = {
|
|
||||||
method: "get",
|
|
||||||
path: "/all",
|
|
||||||
handler: async (req, res) => {
|
|
||||||
if (!req.user) {
|
|
||||||
return res.status(403).send({
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
message: "You are not allowed to perform this action.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const homeFolders = await payload.findGlobal({
|
|
||||||
slug: Collections.HomeFolders,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result =
|
|
||||||
homeFolders.folders?.flatMap<EndpointHomeFolder>(
|
|
||||||
({ folder, darkThumbnail, lightThumbnail }) => {
|
|
||||||
if (!isPayloadType(folder)) return [];
|
|
||||||
if (isEmptyFolder(folder)) return [];
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}),
|
|
||||||
...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}),
|
|
||||||
...convertFolderToPreview(folder),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
) ?? [];
|
|
||||||
|
|
||||||
res.status(200).json(result);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const isEmptyFolder = ({ sections, files }: Folder): boolean =>
|
|
||||||
(!files || files.length === 0) && (!sections || sections.length === 0);
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import { GlobalConfig } from "payload/types";
|
||||||
|
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
|
||||||
|
import { CollectionGroups, Collections } from "../../constants";
|
||||||
|
import { imageField } from "../../fields/imageField/imageField";
|
||||||
|
import { rowField } from "../../fields/rowField/rowField";
|
||||||
|
import { getConfigEndpoint } from "./endpoints/getConfigEndpoint";
|
||||||
|
|
||||||
|
const fields = {
|
||||||
|
homeFolders: "homeFolders",
|
||||||
|
homeFoldersDarkThumbnail: "darkThumbnail",
|
||||||
|
homeFoldersLightThumbnail: "lightThumbnail",
|
||||||
|
homeFoldersFolder: "folder",
|
||||||
|
eras: "eras",
|
||||||
|
name: "name",
|
||||||
|
timeline: "timeline",
|
||||||
|
erasStartingYear: "startingYear",
|
||||||
|
erasEndingYear: "endingYear",
|
||||||
|
erasWording: "name",
|
||||||
|
timelineBreaks: "breaks",
|
||||||
|
} as const satisfies Record<string, string>;
|
||||||
|
|
||||||
|
export const WebsiteConfig: GlobalConfig = {
|
||||||
|
slug: Collections.WebsiteConfig,
|
||||||
|
typescript: { interface: "WebsiteConfig" },
|
||||||
|
admin: {
|
||||||
|
group: CollectionGroups.Meta,
|
||||||
|
},
|
||||||
|
access: { update: mustBeAdmin, read: mustBeAdmin },
|
||||||
|
endpoints: [getConfigEndpoint],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: fields.homeFolders,
|
||||||
|
admin: {
|
||||||
|
description:
|
||||||
|
"These will be the folders displayed on the home page, under the Library section.",
|
||||||
|
},
|
||||||
|
type: "array",
|
||||||
|
fields: [
|
||||||
|
rowField([
|
||||||
|
imageField({ name: fields.homeFoldersLightThumbnail, relationTo: Collections.Images }),
|
||||||
|
imageField({ name: fields.homeFoldersDarkThumbnail, relationTo: Collections.Images }),
|
||||||
|
{
|
||||||
|
name: fields.homeFoldersFolder,
|
||||||
|
type: "relationship",
|
||||||
|
relationTo: Collections.Folders,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fields.timeline,
|
||||||
|
type: "group",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: fields.timelineBreaks,
|
||||||
|
type: "number",
|
||||||
|
hasMany: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fields.eras,
|
||||||
|
type: "array",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: fields.erasWording,
|
||||||
|
type: "relationship",
|
||||||
|
relationTo: Collections.Wordings,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{ name: fields.erasStartingYear, type: "number", required: true, min: 0 },
|
||||||
|
{ name: fields.erasEndingYear, type: "number", required: true, min: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -0,0 +1,51 @@
|
||||||
|
import payload from "payload";
|
||||||
|
import { Collections } from "../../../constants";
|
||||||
|
import { EndpointWebsiteConfig } from "../../../sdk";
|
||||||
|
import { CollectionEndpoint } from "../../../types/payload";
|
||||||
|
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
|
||||||
|
import { convertFolderToPreview } from "../../Folders/endpoints/getBySlugEndpoint";
|
||||||
|
|
||||||
|
export const getConfigEndpoint: CollectionEndpoint = {
|
||||||
|
method: "get",
|
||||||
|
path: "/config",
|
||||||
|
handler: async (req, res) => {
|
||||||
|
if (!req.user) {
|
||||||
|
return res.status(403).send({
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
message: "You are not allowed to perform this action.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { homeFolders, timeline } = await payload.findGlobal({
|
||||||
|
slug: Collections.WebsiteConfig,
|
||||||
|
});
|
||||||
|
|
||||||
|
const endpointWebsiteConfig: EndpointWebsiteConfig = {
|
||||||
|
homeFolders:
|
||||||
|
homeFolders?.flatMap(({ folder, darkThumbnail, lightThumbnail }) => {
|
||||||
|
if (!isPayloadType(folder)) return [];
|
||||||
|
return {
|
||||||
|
...convertFolderToPreview(folder),
|
||||||
|
...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}),
|
||||||
|
...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}),
|
||||||
|
};
|
||||||
|
}) ?? [],
|
||||||
|
timeline: {
|
||||||
|
breaks: timeline?.breaks ?? [],
|
||||||
|
eras:
|
||||||
|
timeline?.eras?.flatMap(({ endingYear, name, startingYear }) => {
|
||||||
|
if (!isPayloadType(name)) return [];
|
||||||
|
return {
|
||||||
|
name: isPayloadType(name) ? name.name : name,
|
||||||
|
startingYear,
|
||||||
|
endingYear,
|
||||||
|
};
|
||||||
|
}) ?? [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
res.status(200).json(endpointWebsiteConfig);
|
||||||
|
},
|
||||||
|
};
|
|
@ -58,7 +58,6 @@ export const Wordings: CollectionConfig = buildCollectionConfig({
|
||||||
name: fields.translations,
|
name: fields.translations,
|
||||||
minRows: 1,
|
minRows: 1,
|
||||||
required: true,
|
required: true,
|
||||||
interfaceName: "CategoryTranslations",
|
|
||||||
admin: {
|
admin: {
|
||||||
useAsTitle: fields.translationsName,
|
useAsTitle: fields.translationsName,
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@ export enum Collections {
|
||||||
Wordings = "wordings",
|
Wordings = "wordings",
|
||||||
Collectibles = "collectibles",
|
Collectibles = "collectibles",
|
||||||
GenericContents = "generic-contents",
|
GenericContents = "generic-contents",
|
||||||
HomeFolders = "home-folders",
|
WebsiteConfig = "website-config",
|
||||||
Videos = "videos",
|
Videos = "videos",
|
||||||
VideosSubtitles = "videos-subtitles",
|
VideosSubtitles = "videos-subtitles",
|
||||||
VideosChannels = "videos-channels",
|
VideosChannels = "videos-channels",
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { Collectibles } from "./collections/Collectibles/Collectibles";
|
||||||
import { Currencies } from "./collections/Currencies/Currencies";
|
import { Currencies } from "./collections/Currencies/Currencies";
|
||||||
import { Folders } from "./collections/Folders/Folders";
|
import { Folders } from "./collections/Folders/Folders";
|
||||||
import { GenericContents } from "./collections/GenericContents/GenericContents";
|
import { GenericContents } from "./collections/GenericContents/GenericContents";
|
||||||
import { HomeFolders } from "./collections/HomeFolders/HomeFolders";
|
|
||||||
import { Images } from "./collections/Images/Images";
|
import { Images } from "./collections/Images/Images";
|
||||||
import { Languages } from "./collections/Languages/Languages";
|
import { Languages } from "./collections/Languages/Languages";
|
||||||
import { Pages } from "./collections/Pages/Pages";
|
import { Pages } from "./collections/Pages/Pages";
|
||||||
|
@ -21,6 +20,7 @@ import { Videos } from "./collections/Videos/Videos";
|
||||||
import { VideosChannels } from "./collections/VideosChannels/VideosChannels";
|
import { VideosChannels } from "./collections/VideosChannels/VideosChannels";
|
||||||
import { VideosSubtitles } from "./collections/VideosSubtitles/VideosSubtitles";
|
import { VideosSubtitles } from "./collections/VideosSubtitles/VideosSubtitles";
|
||||||
import { MediaThumbnails } from "./collections/VideosThumbnails/VideosThumbnails";
|
import { MediaThumbnails } from "./collections/VideosThumbnails/VideosThumbnails";
|
||||||
|
import { WebsiteConfig } from "./collections/WebsiteConfig/WebsiteConfig";
|
||||||
import { Wordings } from "./collections/Wordings/Wordings";
|
import { Wordings } from "./collections/Wordings/Wordings";
|
||||||
import { Icon } from "./components/Icon";
|
import { Icon } from "./components/Icon";
|
||||||
import { Logo } from "./components/Logo";
|
import { Logo } from "./components/Logo";
|
||||||
|
@ -75,7 +75,7 @@ export default buildConfig({
|
||||||
db: mongooseAdapter({
|
db: mongooseAdapter({
|
||||||
url: process.env.MONGODB_URI ?? "",
|
url: process.env.MONGODB_URI ?? "",
|
||||||
}),
|
}),
|
||||||
globals: [HomeFolders],
|
globals: [WebsiteConfig],
|
||||||
telemetry: false,
|
telemetry: false,
|
||||||
typescript: {
|
typescript: {
|
||||||
outputFile: path.resolve(__dirname, "types/collections.ts"),
|
outputFile: path.resolve(__dirname, "types/collections.ts"),
|
||||||
|
|
20
src/sdk.ts
20
src/sdk.ts
|
@ -129,9 +129,19 @@ export type EndpointFolder = EndpointFolderPreview & {
|
||||||
parentPages: EndpointSource[];
|
parentPages: EndpointSource[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointHomeFolder = EndpointFolderPreview & {
|
export type EndpointWebsiteConfig = {
|
||||||
lightThumbnail?: PayloadImage;
|
homeFolders: (EndpointFolderPreview & {
|
||||||
darkThumbnail?: PayloadImage;
|
lightThumbnail?: PayloadImage;
|
||||||
|
darkThumbnail?: PayloadImage;
|
||||||
|
})[];
|
||||||
|
timeline: {
|
||||||
|
breaks: number[];
|
||||||
|
eras: {
|
||||||
|
startingYear: number;
|
||||||
|
endingYear: number;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EndpointRecorder = {
|
export type EndpointRecorder = {
|
||||||
|
@ -322,8 +332,8 @@ export type PayloadImage = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const payload = {
|
export const payload = {
|
||||||
getHomeFolders: async (): Promise<EndpointHomeFolder[]> =>
|
getConfig: async (): Promise<EndpointWebsiteConfig> =>
|
||||||
await (await request(payloadApiUrl(Collections.HomeFolders, `all`, true))).json(),
|
await (await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true))).json(),
|
||||||
getFolder: async (slug: string): Promise<EndpointFolder> =>
|
getFolder: async (slug: string): Promise<EndpointFolder> =>
|
||||||
await (await request(payloadApiUrl(Collections.Folders, `slug/${slug}`))).json(),
|
await (await request(payloadApiUrl(Collections.Folders, `slug/${slug}`))).json(),
|
||||||
getLanguages: async (): Promise<Language[]> =>
|
getLanguages: async (): Promise<Language[]> =>
|
||||||
|
|
|
@ -6,16 +6,6 @@
|
||||||
* and re-run `payload generate:types` to regenerate this file.
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "CategoryTranslations".
|
|
||||||
*/
|
|
||||||
export type CategoryTranslations = {
|
|
||||||
language: string | Language;
|
|
||||||
name: string;
|
|
||||||
id?: string | null;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
collections: {
|
collections: {
|
||||||
pages: Page;
|
pages: Page;
|
||||||
|
@ -40,7 +30,7 @@ export interface Config {
|
||||||
"payload-migrations": PayloadMigration;
|
"payload-migrations": PayloadMigration;
|
||||||
};
|
};
|
||||||
globals: {
|
globals: {
|
||||||
config: Config1;
|
"website-config": WebsiteConfig;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -802,7 +792,11 @@ export interface PageBlock {
|
||||||
export interface Wording {
|
export interface Wording {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
translations: CategoryTranslations;
|
translations: {
|
||||||
|
language: string | Language;
|
||||||
|
name: string;
|
||||||
|
id?: string | null;
|
||||||
|
}[];
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
@ -842,11 +836,11 @@ export interface PayloadMigration {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "config".
|
* via the `definition` "website-config".
|
||||||
*/
|
*/
|
||||||
export interface Config1 {
|
export interface WebsiteConfig {
|
||||||
id: string;
|
id: string;
|
||||||
folders?:
|
homeFolders?:
|
||||||
| {
|
| {
|
||||||
lightThumbnail?: string | Image | null;
|
lightThumbnail?: string | Image | null;
|
||||||
darkThumbnail?: string | Image | null;
|
darkThumbnail?: string | Image | null;
|
||||||
|
@ -854,6 +848,17 @@ export interface Config1 {
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
|
timeline?: {
|
||||||
|
breaks?: number[] | null;
|
||||||
|
eras?:
|
||||||
|
| {
|
||||||
|
name: string | Wording;
|
||||||
|
startingYear: number;
|
||||||
|
endingYear: number;
|
||||||
|
id?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
};
|
||||||
updatedAt?: string | null;
|
updatedAt?: string | null;
|
||||||
createdAt?: string | null;
|
createdAt?: string | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
import { Endpoint } from "payload/config";
|
import { Endpoint } from "payload/config";
|
||||||
import { PayloadRequest } from "payload/types";
|
|
||||||
|
|
||||||
export type CollectionEndpoint = Omit<Endpoint, "root">;
|
export type CollectionEndpoint = Omit<Endpoint, "root">;
|
||||||
|
|
||||||
export type EndpointAccess<U> = (req: PayloadRequest<U>) => boolean;
|
|
||||||
|
|
Loading…
Reference in New Issue