Moved to 2.0
This commit is contained in:
parent
26b4798761
commit
76b7e4a8a2
|
@ -9,7 +9,7 @@ services:
|
||||||
- .:/home/node/app
|
- .:/home/node/app
|
||||||
- node_modules:/home/node/app/node_modules
|
- node_modules:/home/node/app/node_modules
|
||||||
working_dir: /home/node/app/
|
working_dir: /home/node/app/
|
||||||
command: sh -c "npm install && npm run dev"
|
command: sh -c "npm install && npm run generate:types && npm run dev"
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
environment:
|
environment:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -13,21 +13,25 @@
|
||||||
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/",
|
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" 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'",
|
||||||
"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 tsc",
|
"precommit": "npm run generate:types && npm run prettier && npm run unused-exports && npm run tsc",
|
||||||
"upgrade": "ncu",
|
"upgrade": "ncu",
|
||||||
"clean": "sudo rm -r uploads mongo",
|
"clean": "sudo rm -r uploads mongo",
|
||||||
"start": "sudo docker compose up"
|
"start": "sudo docker compose up"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/vollkorn": "^5.0.14",
|
"@fontsource/vollkorn": "^5.0.14",
|
||||||
|
"@payloadcms/bundler-webpack": "^1.0.3",
|
||||||
|
"@payloadcms/db-mongodb": "^1.0.3",
|
||||||
|
"@payloadcms/richtext-lexical": "^0.1.8",
|
||||||
"clean-deep": "^3.4.0",
|
"clean-deep": "^3.4.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"language-tags": "^1.0.9",
|
"language-tags": "^1.0.9",
|
||||||
"luxon": "^3.4.3",
|
"luxon": "^3.4.3",
|
||||||
"payload": "^1.15.7",
|
"payload": "^2.0.5",
|
||||||
"styled-components": "^6.0.8"
|
"styled-components": "^6.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/dotenv": "^8.2.0",
|
"@types/dotenv": "^8.2.0",
|
||||||
|
@ -36,10 +40,12 @@
|
||||||
"@types/luxon": "^3.3.2",
|
"@types/luxon": "^3.3.2",
|
||||||
"@types/qs": "^6.9.8",
|
"@types/qs": "^6.9.8",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
|
"@types/styled-components": "^5.1.28",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
"ts-unused-exports": "^10.0.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { Access } from "payload/config";
|
|
||||||
import { Recorder } from "../../types/collections";
|
|
||||||
import { isDefined, isUndefined } from "../../utils/asserts";
|
|
||||||
|
|
||||||
export const mustHaveAtLeastOneRole: Access<unknown, Recorder> = ({ req: { user } }): boolean => {
|
|
||||||
if (isUndefined(user)) return false;
|
|
||||||
return isDefined(user.role) && user.role.length > 0;
|
|
||||||
};
|
|
|
@ -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 mustBeApi: EndpointAccess<Recorder> = ({ user }) => {
|
|
||||||
if (isUndefined(user)) return false;
|
|
||||||
return isDefined(user.role) && user.role.includes(RecordersRoles.Api);
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { Recorder } from "../../types/collections";
|
|
||||||
import { EndpointAccess } from "../../types/payload";
|
|
||||||
import { isDefined, isUndefined } from "../../utils/asserts";
|
|
||||||
|
|
||||||
export const mustHaveAtLeastOneRole: EndpointAccess<Recorder> = ({ user }) => {
|
|
||||||
if (isUndefined(user)) return false;
|
|
||||||
return isDefined(user.role) && user.role.length > 0;
|
|
||||||
};
|
|
|
@ -50,14 +50,14 @@ export const ChronologyEras: CollectionConfig = buildCollectionConfig({
|
||||||
type: "number",
|
type: "number",
|
||||||
min: 0,
|
min: 0,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%", description: "The year the era started (year included)" },
|
admin: { width: "0%", description: "The year the era started (year included)" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.endingYear,
|
name: fields.endingYear,
|
||||||
type: "number",
|
type: "number",
|
||||||
min: 0,
|
min: 0,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%", description: "The year the era ended (year included)" },
|
admin: { width: "0%", description: "The year the era ended (year included)" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { ChronologyEra } from "../../../types/collections";
|
|
||||||
import { StrapiLanguage } from "../../../types/strapi";
|
import { StrapiLanguage } from "../../../types/strapi";
|
||||||
import { isUndefined } from "../../../utils/asserts";
|
import { isUndefined } from "../../../utils/asserts";
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ type StrapiChronologyEra = {
|
||||||
title: { title: string; language: StrapiLanguage; description?: string }[];
|
title: { title: string; language: StrapiLanguage; description?: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<ChronologyEra, StrapiChronologyEra>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiChronologyEra>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "chronology-eras",
|
collection: "chronology-eras",
|
||||||
params: {
|
params: {
|
||||||
|
|
|
@ -76,10 +76,22 @@ export const ChronologyItems: CollectionConfig = buildVersionedCollectionConfig(
|
||||||
type: "number",
|
type: "number",
|
||||||
required: true,
|
required: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fields.dateMonth,
|
||||||
|
type: "number",
|
||||||
|
min: 1,
|
||||||
|
max: 12,
|
||||||
|
admin: { width: "0%" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fields.dateDay,
|
||||||
|
type: "number",
|
||||||
|
min: 1,
|
||||||
|
max: 31,
|
||||||
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{ name: fields.dateMonth, type: "number", min: 1, max: 12, admin: { width: "33%" } },
|
|
||||||
{ name: fields.dateDay, type: "number", min: 1, max: 31, admin: { width: "33%" } },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { ChronologyItem } from "../../../types/collections";
|
|
||||||
import { StrapiLanguage } from "../../../types/strapi";
|
import { StrapiLanguage } from "../../../types/strapi";
|
||||||
import { isUndefined } from "../../../utils/asserts";
|
import { isUndefined } from "../../../utils/asserts";
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ type StrapiChronologyItem = {
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<ChronologyItem, StrapiChronologyItem>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiChronologyItem>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "chronology-items",
|
collection: "chronology-items",
|
||||||
params: {
|
params: {
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
import { BlocksConfig, generateBlocks } from "../../../utils/recursiveBlocks";
|
|
||||||
import { quoteBlock } from "./quoteBlock";
|
|
||||||
import { textBlock } from "./textBlock";
|
|
||||||
import { transcriptBlock } from "./transcriptBlock";
|
|
||||||
|
|
||||||
const enum BlockName {
|
|
||||||
Text = "Text",
|
|
||||||
Section = "Section",
|
|
||||||
Tabs = "Tabs",
|
|
||||||
Tab = "Tab",
|
|
||||||
Transcript = "Transcript",
|
|
||||||
Quote = "Quote",
|
|
||||||
}
|
|
||||||
|
|
||||||
const blocksConfig: BlocksConfig<BlockName> = {
|
|
||||||
Text: {
|
|
||||||
root: true,
|
|
||||||
block: textBlock,
|
|
||||||
},
|
|
||||||
Section: {
|
|
||||||
root: true,
|
|
||||||
block: {
|
|
||||||
slug: "section",
|
|
||||||
labels: { singular: "Section", plural: "Sections" },
|
|
||||||
recursion: {
|
|
||||||
name: "content",
|
|
||||||
condition: (depth) => depth < 5,
|
|
||||||
newDepth: (depth) => depth + 1,
|
|
||||||
blocks: [
|
|
||||||
BlockName.Section,
|
|
||||||
BlockName.Tabs,
|
|
||||||
BlockName.Transcript,
|
|
||||||
BlockName.Quote,
|
|
||||||
BlockName.Text,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Tabs: {
|
|
||||||
root: true,
|
|
||||||
block: {
|
|
||||||
slug: "tabs",
|
|
||||||
labels: { singular: "Tabs", plural: "Tabs" },
|
|
||||||
recursion: {
|
|
||||||
name: "tabs",
|
|
||||||
newDepth: (depth) => depth,
|
|
||||||
condition: (depth, parents) => !parents.includes(BlockName.Tabs) && depth < 5,
|
|
||||||
blocks: [BlockName.Tab],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Tab: {
|
|
||||||
root: false,
|
|
||||||
block: {
|
|
||||||
slug: "tab",
|
|
||||||
labels: { singular: "Tab", plural: "Tabs" },
|
|
||||||
recursion: {
|
|
||||||
name: "content",
|
|
||||||
condition: (depth) => depth < 5,
|
|
||||||
newDepth: (depth) => depth + 1,
|
|
||||||
blocks: [
|
|
||||||
BlockName.Section,
|
|
||||||
BlockName.Tabs,
|
|
||||||
BlockName.Transcript,
|
|
||||||
BlockName.Quote,
|
|
||||||
BlockName.Text,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Transcript: {
|
|
||||||
root: true,
|
|
||||||
block: transcriptBlock,
|
|
||||||
},
|
|
||||||
Quote: {
|
|
||||||
root: true,
|
|
||||||
block: quoteBlock,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const contentBlocks = generateBlocks(blocksConfig);
|
|
|
@ -10,11 +10,6 @@ export const lineBlock: Block = {
|
||||||
label: false,
|
label: false,
|
||||||
type: "richText",
|
type: "richText",
|
||||||
required: true,
|
required: true,
|
||||||
admin: {
|
|
||||||
hideGutter: true,
|
|
||||||
elements: [],
|
|
||||||
leaves: ["bold", "italic", "underline", "strikethrough", "code"],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { Block } from "payload/types";
|
|
||||||
|
|
||||||
export const quoteBlock: Block = {
|
|
||||||
slug: "quoteBlock",
|
|
||||||
interfaceName: "QuoteBlock",
|
|
||||||
labels: { singular: "Quote", plural: "Quotes" },
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "from",
|
|
||||||
type: "text",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "content",
|
|
||||||
type: "richText",
|
|
||||||
label: false,
|
|
||||||
required: true,
|
|
||||||
admin: {
|
|
||||||
hideGutter: true,
|
|
||||||
elements: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { Block } from "payload/types";
|
|
||||||
|
|
||||||
export const textBlock: Block = {
|
|
||||||
slug: "textBlock",
|
|
||||||
interfaceName: "TextBlock",
|
|
||||||
labels: { singular: "Text", plural: "Texts" },
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "content",
|
|
||||||
type: "richText",
|
|
||||||
label: false,
|
|
||||||
required: true,
|
|
||||||
admin: {
|
|
||||||
hideGutter: true,
|
|
||||||
elements: ["ul", "ol", "indent", "link", "relationship", "upload", "blockquote"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
|
@ -9,7 +9,6 @@ import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping";
|
||||||
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
|
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
|
||||||
import { isDefined } from "../../utils/asserts";
|
import { isDefined } from "../../utils/asserts";
|
||||||
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
|
||||||
import { contentBlocks } from "./Blocks/blocks";
|
|
||||||
|
|
||||||
const fields = {
|
const fields = {
|
||||||
slug: "slug",
|
slug: "slug",
|
||||||
|
@ -66,11 +65,11 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
slugField({ name: fields.slug, admin: { width: "50%" } }),
|
slugField({ name: fields.slug, admin: { width: "0%" } }),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.thumbnail,
|
name: fields.thumbnail,
|
||||||
relationTo: Collections.ContentsThumbnails,
|
relationTo: Collections.ContentsThumbnails,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -81,12 +80,12 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
name: fields.categories,
|
name: fields.categories,
|
||||||
relationTo: KeysTypes.Categories,
|
relationTo: KeysTypes.Categories,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
keysField({
|
keysField({
|
||||||
name: fields.type,
|
name: fields.type,
|
||||||
relationTo: KeysTypes.Contents,
|
relationTo: KeysTypes.Contents,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -115,6 +114,7 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
{
|
{
|
||||||
label: "Text",
|
label: "Text",
|
||||||
fields: [
|
fields: [
|
||||||
|
{ name: fields.textContent, type: "richText" },
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
|
@ -127,7 +127,7 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) =>
|
condition: (_, siblingData) =>
|
||||||
siblingData.language === siblingData.sourceLanguage,
|
siblingData.language === siblingData.sourceLanguage,
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -139,7 +139,7 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) =>
|
condition: (_, siblingData) =>
|
||||||
siblingData.language !== siblingData.sourceLanguage,
|
siblingData.language !== siblingData.sourceLanguage,
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -148,18 +148,10 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Recorders,
|
relationTo: Collections.Recorders,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: fields.textContent,
|
|
||||||
label: "Content",
|
|
||||||
labels: { singular: "Block", plural: "Blocks" },
|
|
||||||
type: "blocks",
|
|
||||||
admin: { initCollapsed: true },
|
|
||||||
blocks: contentBlocks,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: fields.textNotes,
|
name: fields.textNotes,
|
||||||
label: "Notes",
|
label: "Notes",
|
||||||
|
@ -176,13 +168,13 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
fileField({
|
fileField({
|
||||||
name: fields.video,
|
name: fields.video,
|
||||||
relationTo: FileTypes.ContentVideo,
|
relationTo: FileTypes.ContentVideo,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: fields.videoNotes,
|
name: fields.videoNotes,
|
||||||
label: "Notes",
|
label: "Notes",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -197,13 +189,13 @@ export const Contents = buildVersionedCollectionConfig({
|
||||||
fileField({
|
fileField({
|
||||||
name: fields.audio,
|
name: fields.audio,
|
||||||
relationTo: FileTypes.ContentAudio,
|
relationTo: FileTypes.ContentAudio,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: fields.audioNotes,
|
name: fields.audioNotes,
|
||||||
label: "Notes",
|
label: "Notes",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,14 +44,14 @@ export const ContentsFolders = buildCollectionConfig({
|
||||||
name: fields.subfolders,
|
name: fields.subfolders,
|
||||||
relationTo: Collections.ContentsFolders,
|
relationTo: Collections.ContentsFolders,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
name: fields.contents,
|
name: fields.contents,
|
||||||
relationTo: Collections.Contents,
|
relationTo: Collections.Contents,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Language } from "../../../types/collections";
|
|
||||||
|
|
||||||
type StrapiLanguage = {
|
type StrapiLanguage = {
|
||||||
code: string;
|
code: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<Language, StrapiLanguage>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiLanguage>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "currencies",
|
collection: "currencies",
|
||||||
params: {},
|
params: {},
|
||||||
|
|
|
@ -102,7 +102,7 @@ export const Keys = buildCollectionConfig({
|
||||||
name: fields.translationsName,
|
name: fields.translationsName,
|
||||||
type: "text",
|
type: "text",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.translationsShort,
|
name: fields.translationsShort,
|
||||||
|
@ -110,7 +110,7 @@ export const Keys = buildCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
condition: (data: Partial<Key>) =>
|
condition: (data: Partial<Key>) =>
|
||||||
isDefined(data.type) && keysTypesWithShort.includes(data.type),
|
isDefined(data.type) && keysTypesWithShort.includes(data.type),
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -5,51 +5,45 @@ import {
|
||||||
importStrapiEntries,
|
importStrapiEntries,
|
||||||
} from "../../../endpoints/createStrapiImportEndpoint";
|
} from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Key } from "../../../types/collections";
|
import { Key } from "../../../types/collections";
|
||||||
import { CollectionEndpoint, PayloadCreateData } from "../../../types/payload";
|
import { CollectionEndpoint } from "../../../types/payload";
|
||||||
import { StrapiLanguage } from "../../../types/strapi";
|
import { StrapiLanguage } from "../../../types/strapi";
|
||||||
import { isDefined, isUndefined } from "../../../utils/asserts";
|
import { isDefined, isUndefined } from "../../../utils/asserts";
|
||||||
import { formatToCamelCase } from "../../../utils/string";
|
import { formatToCamelCase } from "../../../utils/string";
|
||||||
|
|
||||||
const importStrapiWordings: typeof importStrapiEntries = async ({
|
const importStrapiWordings: typeof importStrapiEntries = async ({ strapi: strapiParams, user }) => {
|
||||||
payload: payloadParams,
|
const rawEntries = await getAllStrapiEntries(strapiParams.collection, strapiParams.params);
|
||||||
strapi: strapiParams,
|
|
||||||
user,
|
|
||||||
}) => {
|
|
||||||
const rawEntries = await getAllStrapiEntries<any>(strapiParams.collection, strapiParams.params);
|
|
||||||
|
|
||||||
const { ui_language, createdAt, updatedAt, ...otherKeys } = rawEntries[0].attributes;
|
const { ui_language, createdAt, updatedAt, ...otherKeys } = rawEntries[0].attributes;
|
||||||
|
|
||||||
const entries: PayloadCreateData<Key>[] = Object.keys(otherKeys).map((key) => ({
|
|
||||||
name: formatToCamelCase(key),
|
|
||||||
type: "Wordings",
|
|
||||||
translations: rawEntries
|
|
||||||
.map((entry) => ({
|
|
||||||
language: entry.attributes.ui_language.data.attributes.code,
|
|
||||||
name: entry.attributes[key],
|
|
||||||
}))
|
|
||||||
.filter(({ name }) => isDefined(name) && name !== ""),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
entries.map(async (entry) => {
|
Object.keys(otherKeys).map(async (key) => {
|
||||||
try {
|
try {
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: payloadParams.collection,
|
collection: Collections.Keys,
|
||||||
data: entry,
|
data: {
|
||||||
|
name: formatToCamelCase(key),
|
||||||
|
type: "Wordings",
|
||||||
|
translations: rawEntries
|
||||||
|
.map((entry) => ({
|
||||||
|
language: entry.attributes.ui_language.data.attributes.code,
|
||||||
|
name: entry.attributes[key],
|
||||||
|
}))
|
||||||
|
.filter(({ name }) => isDefined(name) && name !== ""),
|
||||||
|
},
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
if (typeof e === "object" && isDefined(e) && "name" in e) {
|
if (typeof e === "object" && isDefined(e) && "name" in e) {
|
||||||
errors.push(`${e.name} with ${entry.name}`);
|
errors.push(`${e.name} with ${key}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return { count: entries.length, errors };
|
return { count: Object.keys(otherKeys).length, errors };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi: CollectionEndpoint = {
|
export const importFromStrapi: CollectionEndpoint = {
|
||||||
|
@ -71,289 +65,271 @@ export const importFromStrapi: CollectionEndpoint = {
|
||||||
titles: { title?: string; short?: string; language: StrapiLanguage }[];
|
titles: { title?: string; short?: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: categoriesCount, errors: categoriesErrors } = await importStrapiEntries<
|
const { count: categoriesCount, errors: categoriesErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiCategories>({
|
||||||
StrapiCategories
|
strapi: {
|
||||||
>({
|
collection: "categories",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "categories",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "Categories",
|
||||||
name: slug,
|
translations: titles.map(({ title, short, language }) => {
|
||||||
type: "Categories",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, short, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
if (isUndefined(title))
|
||||||
throw new Error("A language is required for a Keys title translation");
|
throw new Error("A title is required for a Keys title translation");
|
||||||
if (isUndefined(title))
|
return {
|
||||||
throw new Error("A title is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
short,
|
||||||
name: title,
|
language: language.data.attributes.code,
|
||||||
short,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiContentType = {
|
type StrapiContentType = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: contentTypesCount, errors: contentTypesErrors } = await importStrapiEntries<
|
const { count: contentTypesCount, errors: contentTypesErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiContentType>({
|
||||||
StrapiContentType
|
strapi: {
|
||||||
>({
|
collection: "content-types",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "content-types",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "Contents",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "Contents",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiGamePlatform = {
|
type StrapiGamePlatform = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title?: string; short?: string; language: StrapiLanguage }[];
|
titles: { title?: string; short?: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: gamePlatformsCount, errors: gamePlatformsErrors } = await importStrapiEntries<
|
const { count: gamePlatformsCount, errors: gamePlatformsErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiGamePlatform>({
|
||||||
StrapiGamePlatform
|
strapi: {
|
||||||
>({
|
collection: "game-platforms",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "game-platforms",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "GamePlatforms",
|
||||||
name: slug,
|
translations: titles.map(({ title, short, language }) => {
|
||||||
type: "GamePlatforms",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, short, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
if (isUndefined(title))
|
||||||
throw new Error("A language is required for a Keys title translation");
|
throw new Error("A title is required for a Keys title translation");
|
||||||
if (isUndefined(title))
|
return {
|
||||||
throw new Error("A title is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
short,
|
||||||
name: title,
|
language: language.data.attributes.code,
|
||||||
short,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiMetadataTypes = {
|
type StrapiMetadataTypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: libraryCount, errors: libraryErrors } = await importStrapiEntries<
|
const { count: libraryCount, errors: libraryErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiMetadataTypes>({
|
||||||
StrapiMetadataTypes
|
strapi: {
|
||||||
>({
|
collection: "metadata-types",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "metadata-types",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "Library",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "Library",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiAudioSubtypes = {
|
type StrapiAudioSubtypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: libraryAudioCount, errors: libraryAudioErrors } = await importStrapiEntries<
|
const { count: libraryAudioCount, errors: libraryAudioErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiAudioSubtypes>({
|
||||||
StrapiAudioSubtypes
|
strapi: {
|
||||||
>({
|
collection: "audio-subtypes",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "audio-subtypes",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "LibraryAudio",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "LibraryAudio",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiGroupSubtypes = {
|
type StrapiGroupSubtypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: libraryGroupCount, errors: libraryGroupErrors } = await importStrapiEntries<
|
const { count: libraryGroupCount, errors: libraryGroupErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiGroupSubtypes>({
|
||||||
StrapiGroupSubtypes
|
strapi: {
|
||||||
>({
|
collection: "group-subtypes",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "group-subtypes",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "LibraryGroup",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "LibraryGroup",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiTextualSubtypes = {
|
type StrapiTextualSubtypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: libraryTextualCount, errors: libraryTextualErrors } = await importStrapiEntries<
|
const { count: libraryTextualCount, errors: libraryTextualErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiTextualSubtypes>({
|
||||||
StrapiTextualSubtypes
|
strapi: {
|
||||||
>({
|
collection: "textual-subtypes",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "textual-subtypes",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "LibraryTextual",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "LibraryTextual",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiVideoSubtypes = {
|
type StrapiVideoSubtypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
titles: { title: string; language: StrapiLanguage }[];
|
titles: { title: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: libraryVideoCount, errors: libraryVideoErrors } = await importStrapiEntries<
|
const { count: libraryVideoCount, errors: libraryVideoErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiVideoSubtypes>({
|
||||||
StrapiVideoSubtypes
|
strapi: {
|
||||||
>({
|
collection: "video-subtypes",
|
||||||
strapi: {
|
params: { populate: { titles: { populate: "language" } } },
|
||||||
collection: "video-subtypes",
|
},
|
||||||
params: { populate: { titles: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, titles }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, titles }) => ({
|
type: "LibraryVideo",
|
||||||
name: slug,
|
translations: titles.map(({ title, language }) => {
|
||||||
type: "LibraryVideo",
|
if (isUndefined(language.data))
|
||||||
translations: titles.map(({ title, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
return {
|
||||||
throw new Error("A language is required for a Keys title translation");
|
name: title,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name: title,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
type StrapiWeaponTypes = {
|
type StrapiWeaponTypes = {
|
||||||
slug: string;
|
slug: string;
|
||||||
translations: { name?: string; language: StrapiLanguage }[];
|
translations: { name?: string; language: StrapiLanguage }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { count: weaponsCount, errors: weaponsErrors } = await importStrapiEntries<
|
const { count: weaponsCount, errors: weaponsErrors } =
|
||||||
Key,
|
await importStrapiEntries<StrapiWeaponTypes>({
|
||||||
StrapiWeaponTypes
|
strapi: {
|
||||||
>({
|
collection: "weapon-story-types",
|
||||||
strapi: {
|
params: { populate: { translations: { populate: "language" } } },
|
||||||
collection: "weapon-story-types",
|
},
|
||||||
params: { populate: { translations: { populate: "language" } } },
|
payload: {
|
||||||
},
|
collection: Collections.Keys,
|
||||||
payload: {
|
convert: ({ slug, translations }) => ({
|
||||||
collection: Collections.Keys,
|
name: slug,
|
||||||
convert: ({ slug, translations }) => ({
|
type: "Weapons",
|
||||||
name: slug,
|
translations: translations.map(({ name, language }) => {
|
||||||
type: "Weapons",
|
if (isUndefined(language.data))
|
||||||
translations: translations.map(({ name, language }) => {
|
throw new Error("A language is required for a Keys title translation");
|
||||||
if (isUndefined(language.data))
|
if (isUndefined(name))
|
||||||
throw new Error("A language is required for a Keys title translation");
|
throw new Error("A name is required for a Keys title translation");
|
||||||
if (isUndefined(name))
|
return {
|
||||||
throw new Error("A name is required for a Keys title translation");
|
name,
|
||||||
return {
|
language: language.data.attributes.code,
|
||||||
name,
|
};
|
||||||
language: language.data.attributes.code,
|
}),
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
user: req.user,
|
||||||
user: req.user,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const { count: wordingsCount, errors: wordingsErrors } = await importStrapiWordings<Key, Key>({
|
const { count: wordingsCount, errors: wordingsErrors } = await importStrapiWordings<Key>({
|
||||||
strapi: { collection: "website-interfaces", params: { populate: "ui_language" } },
|
strapi: { collection: "website-interfaces", params: { populate: "ui_language" } },
|
||||||
payload: { collection: Collections.Keys, convert: (strapiObject) => strapiObject },
|
payload: { collection: Collections.Keys, convert: (strapiObject) => strapiObject },
|
||||||
user: req.user,
|
user: req.user,
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Language } from "../../../types/collections";
|
|
||||||
|
|
||||||
type StrapiLanguage = {
|
type StrapiLanguage = {
|
||||||
name: string;
|
name: string;
|
||||||
code: string;
|
code: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<Language, StrapiLanguage>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiLanguage>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "languages",
|
collection: "languages",
|
||||||
params: {},
|
params: {},
|
||||||
|
|
|
@ -170,12 +170,10 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
fields: [
|
fields: [
|
||||||
slugField({
|
slugField({
|
||||||
name: fields.slug,
|
name: fields.slug,
|
||||||
admin: { width: "50%" },
|
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.thumbnail,
|
name: fields.thumbnail,
|
||||||
relationTo: Collections.LibraryItemsThumbnails,
|
relationTo: Collections.LibraryItemsThumbnails,
|
||||||
admin: { width: "50%" },
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -197,7 +195,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
admin: {
|
admin: {
|
||||||
description: "Only items that can be sold separetely should be root items.",
|
description: "Only items that can be sold separetely should be root items.",
|
||||||
width: "25%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -208,7 +206,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
description:
|
description:
|
||||||
"A primary item is an official item that focuses primarly on one or more of our Categories.",
|
"A primary item is an official item that focuses primarly on one or more of our Categories.",
|
||||||
width: "25%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -219,7 +217,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
description:
|
description:
|
||||||
"The item is the digital version of another item, or the item is sold only digitally.",
|
"The item is the digital version of another item, or the item is sold only digitally.",
|
||||||
width: "25%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -229,7 +227,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
admin: {
|
admin: {
|
||||||
description: "Are the scans available for download?",
|
description: "Are the scans available for download?",
|
||||||
width: "25%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -265,17 +263,17 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverFront,
|
name: fields.scansCoverFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverSpine,
|
name: fields.scansCoverSpine,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverBack,
|
name: fields.scansCoverBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -285,12 +283,12 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverInsideFront,
|
name: fields.scansCoverInsideFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverBack,
|
name: fields.scansCoverBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -300,22 +298,22 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverFlapFront,
|
name: fields.scansCoverFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverFlapBack,
|
name: fields.scansCoverFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverInsideFlapFront,
|
name: fields.scansCoverInsideFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansCoverInsideFlapBack,
|
name: fields.scansCoverInsideFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -337,17 +335,17 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketFront,
|
name: fields.scansDustjacketFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketSpine,
|
name: fields.scansDustjacketSpine,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketBack,
|
name: fields.scansDustjacketBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -357,17 +355,17 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketInsideFront,
|
name: fields.scansDustjacketInsideFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketInsideSpine,
|
name: fields.scansDustjacketInsideSpine,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketInsideBack,
|
name: fields.scansDustjacketInsideBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -377,22 +375,22 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketFlapFront,
|
name: fields.scansDustjacketFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketFlapBack,
|
name: fields.scansDustjacketFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketInsideFlapFront,
|
name: fields.scansDustjacketInsideFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansDustjacketInsideFlapBack,
|
name: fields.scansDustjacketInsideFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -414,17 +412,17 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiFront,
|
name: fields.scansObiFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiSpine,
|
name: fields.scansObiSpine,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiBack,
|
name: fields.scansObiBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -434,17 +432,17 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiInsideFront,
|
name: fields.scansObiInsideFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiInsideSpine,
|
name: fields.scansObiInsideSpine,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiInsideBack,
|
name: fields.scansObiInsideBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -454,22 +452,22 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiFlapFront,
|
name: fields.scansObiFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiFlapBack,
|
name: fields.scansObiFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiInsideFlapFront,
|
name: fields.scansObiInsideFlapFront,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansObiInsideFlapBack,
|
name: fields.scansObiInsideFlapBack,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
admin: { width: "25%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -495,13 +493,13 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.scansPagesPage,
|
name: fields.scansPagesPage,
|
||||||
type: "number",
|
type: "number",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.scansPagesImage,
|
name: fields.scansPagesImage,
|
||||||
relationTo: Collections.LibraryItemsScans,
|
relationTo: Collections.LibraryItemsScans,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "66%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -518,6 +516,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
{
|
{
|
||||||
name: fields.textual,
|
name: fields.textual,
|
||||||
type: "group",
|
type: "group",
|
||||||
|
label: false,
|
||||||
admin: {
|
admin: {
|
||||||
condition: (data: Partial<LibraryItem>) =>
|
condition: (data: Partial<LibraryItem>) =>
|
||||||
data.itemType === LibraryItemsTypes.Textual,
|
data.itemType === LibraryItemsTypes.Textual,
|
||||||
|
@ -530,14 +529,14 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.textualSubtype,
|
name: fields.textualSubtype,
|
||||||
relationTo: KeysTypes.LibraryTextual,
|
relationTo: KeysTypes.LibraryTextual,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: fields.textualLanguages,
|
name: fields.textualLanguages,
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Languages,
|
relationTo: Collections.Languages,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -548,7 +547,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.textualPageCount,
|
name: fields.textualPageCount,
|
||||||
type: "number",
|
type: "number",
|
||||||
min: 1,
|
min: 1,
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.textualBindingType,
|
name: fields.textualBindingType,
|
||||||
|
@ -561,7 +560,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
),
|
),
|
||||||
admin: {
|
admin: {
|
||||||
layout: "horizontal",
|
layout: "horizontal",
|
||||||
width: "33%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -575,7 +574,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
),
|
),
|
||||||
admin: {
|
admin: {
|
||||||
layout: "horizontal",
|
layout: "horizontal",
|
||||||
width: "33%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -585,6 +584,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
{
|
{
|
||||||
name: fields.audio,
|
name: fields.audio,
|
||||||
type: "group",
|
type: "group",
|
||||||
|
label: false,
|
||||||
admin: {
|
admin: {
|
||||||
condition: (data: Partial<LibraryItem>) =>
|
condition: (data: Partial<LibraryItem>) =>
|
||||||
data.itemType === LibraryItemsTypes.Audio,
|
data.itemType === LibraryItemsTypes.Audio,
|
||||||
|
@ -597,7 +597,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.audioSubtype,
|
name: fields.audioSubtype,
|
||||||
relationTo: KeysTypes.LibraryAudio,
|
relationTo: KeysTypes.LibraryAudio,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -612,13 +612,13 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.audioTracksTitle,
|
name: fields.audioTracksTitle,
|
||||||
type: "text",
|
type: "text",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
fileField({
|
fileField({
|
||||||
name: fields.audioTracksFile,
|
name: fields.audioTracksFile,
|
||||||
relationTo: FileTypes.LibrarySoundtracks,
|
relationTo: FileTypes.LibrarySoundtracks,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -639,21 +639,21 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
type: "date",
|
type: "date",
|
||||||
admin: {
|
admin: {
|
||||||
date: { pickerAppearance: "dayOnly", displayFormat: "yyyy-MM-dd" },
|
date: { pickerAppearance: "dayOnly", displayFormat: "yyyy-MM-dd" },
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
keysField({
|
keysField({
|
||||||
name: fields.categories,
|
name: fields.categories,
|
||||||
relationTo: KeysTypes.Categories,
|
relationTo: KeysTypes.Categories,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
translatedFields({
|
translatedFields({
|
||||||
name: fields.translations,
|
name: fields.translations,
|
||||||
label: "Descriptions",
|
label: "Descriptions",
|
||||||
admin: { initCollapsed: true },
|
admin: { initCollapsed: true, useAsTitle: fields.translationsDescription },
|
||||||
fields: [{ name: fields.translationsDescription, type: "textarea", required: true }],
|
fields: [{ name: fields.translationsDescription, type: "textarea", required: true }],
|
||||||
}),
|
}),
|
||||||
optionalGroupField({
|
optionalGroupField({
|
||||||
|
@ -667,18 +667,18 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
name: fields.width,
|
name: fields.width,
|
||||||
type: "number",
|
type: "number",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { step: 1, width: "33%", description: "in mm." },
|
admin: { step: 1, width: "0%", description: "in mm." },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.height,
|
name: fields.height,
|
||||||
type: "number",
|
type: "number",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { step: 1, width: "33%", description: "in mm." },
|
admin: { step: 1, width: "0%", description: "in mm." },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.thickness,
|
name: fields.thickness,
|
||||||
type: "number",
|
type: "number",
|
||||||
admin: { step: 1, width: "33%", description: "in mm." },
|
admin: { step: 1, width: "0%", description: "in mm." },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -686,7 +686,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
}),
|
}),
|
||||||
optionalGroupField({
|
optionalGroupField({
|
||||||
name: fields.price,
|
name: fields.price,
|
||||||
admin: { className: "group-array", width: "50%" },
|
admin: { className: "group-array", width: "0%" },
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
|
@ -696,14 +696,14 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
type: "number",
|
type: "number",
|
||||||
required: true,
|
required: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.priceCurrency,
|
name: fields.priceCurrency,
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Currencies,
|
relationTo: Collections.Currencies,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -715,7 +715,7 @@ export const LibraryItems = buildVersionedCollectionConfig({
|
||||||
type: "array",
|
type: "array",
|
||||||
admin: {
|
admin: {
|
||||||
description: "Links to official websites where to get/buy the item.",
|
description: "Links to official websites where to get/buy the item.",
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
fields: [{ name: fields.urlsUrl, type: "text", required: true }],
|
fields: [{ name: fields.urlsUrl, type: "text", required: true }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { styled } from "styled-components";
|
import styled from "styled-components";
|
||||||
import { isDefined } from "../../../utils/asserts";
|
import { isDefined } from "../../../utils/asserts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
|
@ -60,11 +60,11 @@ export const Posts = buildVersionedCollectionConfig({
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
slugField({ name: fields.slug, admin: { width: "50%" } }),
|
slugField({ name: fields.slug, admin: { width: "0%" } }),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.thumbnail,
|
name: fields.thumbnail,
|
||||||
relationTo: Collections.PostsThumbnails,
|
relationTo: Collections.PostsThumbnails,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -78,7 +78,7 @@ export const Posts = buildVersionedCollectionConfig({
|
||||||
required: true,
|
required: true,
|
||||||
minRows: 1,
|
minRows: 1,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "35%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.categories,
|
name: fields.categories,
|
||||||
|
@ -86,7 +86,7 @@ export const Posts = buildVersionedCollectionConfig({
|
||||||
relationTo: [Collections.Keys],
|
relationTo: [Collections.Keys],
|
||||||
filterOptions: { type: { equals: KeysTypes.Categories } },
|
filterOptions: { type: { equals: KeysTypes.Categories } },
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { allowCreate: false, width: "35%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -125,7 +125,7 @@ export const Posts = buildVersionedCollectionConfig({
|
||||||
}
|
}
|
||||||
return siblingData.language !== siblingData.sourceLanguage;
|
return siblingData.language !== siblingData.sourceLanguage;
|
||||||
},
|
},
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
validate: (translators, { siblingData }) => {
|
validate: (translators, { siblingData }) => {
|
||||||
if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) {
|
if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) {
|
||||||
|
@ -145,11 +145,11 @@ export const Posts = buildVersionedCollectionConfig({
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Recorders,
|
relationTo: Collections.Recorders,
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ name: fields.content, type: "richText", admin: { hideGutter: true } },
|
{ name: fields.content, type: "richText" },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,12 +84,12 @@ export const Recorders = buildCollectionConfig({
|
||||||
type: "text",
|
type: "text",
|
||||||
unique: true,
|
unique: true,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { description: "The username must be unique", width: "33%" },
|
admin: { description: "The username must be unique", width: "0%" },
|
||||||
},
|
},
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.avatar,
|
name: fields.avatar,
|
||||||
relationTo: Collections.RecordersThumbnails,
|
relationTo: Collections.RecordersThumbnails,
|
||||||
admin: { width: "66%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,6 @@ import payload from "payload";
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Recorder } from "../../../types/collections";
|
import { Recorder } from "../../../types/collections";
|
||||||
import { PayloadCreateData } from "../../../types/payload";
|
|
||||||
import { StrapiImage, StrapiLanguage } from "../../../types/strapi";
|
import { StrapiImage, StrapiLanguage } from "../../../types/strapi";
|
||||||
import { isDefined, isUndefined } from "../../../utils/asserts";
|
import { isDefined, isUndefined } from "../../../utils/asserts";
|
||||||
import { uploadStrapiImage } from "../../../utils/localApi";
|
import { uploadStrapiImage } from "../../../utils/localApi";
|
||||||
|
@ -16,7 +15,7 @@ type StrapiRecorder = {
|
||||||
bio: { language: StrapiLanguage; bio?: string }[];
|
bio: { language: StrapiLanguage; bio?: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<Recorder, StrapiRecorder>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiRecorder>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "recorders",
|
collection: "recorders",
|
||||||
params: {
|
params: {
|
||||||
|
@ -31,22 +30,6 @@ export const importFromStrapi = createStrapiImportEndpoint<Recorder, StrapiRecor
|
||||||
image: avatar,
|
image: avatar,
|
||||||
});
|
});
|
||||||
|
|
||||||
const data: Omit<PayloadCreateData<Recorder>, "password" | "email"> = {
|
|
||||||
username,
|
|
||||||
anonymize,
|
|
||||||
languages: languages.data?.map((language) => language.attributes.code),
|
|
||||||
avatar: avatarId,
|
|
||||||
biographies: bios?.map(({ language, bio }) => {
|
|
||||||
if (isUndefined(language.data))
|
|
||||||
throw new Error("A language is required for a Recorder biography");
|
|
||||||
if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography");
|
|
||||||
return {
|
|
||||||
language: language.data.attributes.code,
|
|
||||||
biography: bio,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
const recorder = (
|
const recorder = (
|
||||||
await payload.find({
|
await payload.find({
|
||||||
collection: Collections.Recorders,
|
collection: Collections.Recorders,
|
||||||
|
@ -55,12 +38,44 @@ export const importFromStrapi = createStrapiImportEndpoint<Recorder, StrapiRecor
|
||||||
).docs[0] as Recorder | undefined;
|
).docs[0] as Recorder | undefined;
|
||||||
|
|
||||||
if (isDefined(recorder)) {
|
if (isDefined(recorder)) {
|
||||||
await payload.update({ collection: Collections.Recorders, id: recorder.id, data, user });
|
await payload.update({
|
||||||
|
collection: Collections.Recorders,
|
||||||
|
id: recorder.id,
|
||||||
|
data: {
|
||||||
|
username,
|
||||||
|
anonymize,
|
||||||
|
languages: languages.data?.map((language) => language.attributes.code),
|
||||||
|
avatar: avatarId,
|
||||||
|
biographies: bios?.map(({ language, bio }) => {
|
||||||
|
if (isUndefined(language.data))
|
||||||
|
throw new Error("A language is required for a Recorder biography");
|
||||||
|
if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography");
|
||||||
|
return {
|
||||||
|
language: language.data.attributes.code,
|
||||||
|
biography: bio,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
user,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: Collections.Recorders,
|
collection: Collections.Recorders,
|
||||||
data: {
|
data: {
|
||||||
...data,
|
username,
|
||||||
|
anonymize,
|
||||||
|
languages: languages.data?.map((language) => language.attributes.code),
|
||||||
|
avatar: avatarId,
|
||||||
|
biographies: bios?.map(({ language, bio }) => {
|
||||||
|
if (isUndefined(language.data))
|
||||||
|
throw new Error("A language is required for a Recorder biography");
|
||||||
|
if (isUndefined(bio)) throw new Error("A bio is required for a Recorder biography");
|
||||||
|
return {
|
||||||
|
language: language.data.attributes.code,
|
||||||
|
biography: bio,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
email: `${anonymous_code}@accords-library.com`,
|
email: `${anonymous_code}@accords-library.com`,
|
||||||
password: process.env.RECORDER_DEFAULT_PASSWORD,
|
password: process.env.RECORDER_DEFAULT_PASSWORD,
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,7 @@ export const Videos: CollectionConfig = buildCollectionConfig({
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
{ name: fields.uid, type: "text", required: true, unique: true, admin: { width: "33%" } },
|
{ name: fields.uid, type: "text", required: true, unique: true, admin: { width: "0%" } },
|
||||||
{
|
{
|
||||||
name: fields.gone,
|
name: fields.gone,
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
|
@ -59,7 +59,7 @@ export const Videos: CollectionConfig = buildCollectionConfig({
|
||||||
admin: {
|
admin: {
|
||||||
description:
|
description:
|
||||||
"Is the video no longer available (deleted, privatized, unlisted, blocked...)",
|
"Is the video no longer available (deleted, privatized, unlisted, blocked...)",
|
||||||
width: "33%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ export const Videos: CollectionConfig = buildCollectionConfig({
|
||||||
type: "select",
|
type: "select",
|
||||||
required: true,
|
required: true,
|
||||||
options: Object.entries(VideoSources).map(([value, label]) => ({ label, value })),
|
options: Object.entries(VideoSources).map(([value, label]) => ({ label, value })),
|
||||||
admin: { width: "33%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -77,8 +77,8 @@ export const Videos: CollectionConfig = buildCollectionConfig({
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
{ name: fields.likes, type: "number", admin: { width: "50%" } },
|
{ name: fields.likes, type: "number", admin: { width: "0%" } },
|
||||||
{ name: fields.views, type: "number", admin: { width: "50%" } },
|
{ name: fields.views, type: "number", admin: { width: "0%" } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import payload from "payload";
|
import payload from "payload";
|
||||||
import { Collections, VideoSources } from "../../../constants";
|
import { Collections, VideoSources } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Video, VideosChannel } from "../../../types/collections";
|
|
||||||
import { PayloadCreateData } from "../../../types/payload";
|
|
||||||
import { isDefined, isUndefined } from "../../../utils/asserts";
|
import { isDefined, isUndefined } from "../../../utils/asserts";
|
||||||
|
|
||||||
type StapiVideo = {
|
type StapiVideo = {
|
||||||
|
@ -21,7 +19,7 @@ type StapiVideo = {
|
||||||
channel: { data?: { attributes: { uid: string; title: string; subscribers: number } } };
|
channel: { data?: { attributes: { uid: string; title: string; subscribers: number } } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<Video, StapiVideo>({
|
export const importFromStrapi = createStrapiImportEndpoint<StapiVideo>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "videos",
|
collection: "videos",
|
||||||
params: { populate: "published_date,channel" },
|
params: { populate: "published_date,channel" },
|
||||||
|
@ -49,14 +47,13 @@ export const importFromStrapi = createStrapiImportEndpoint<Video, StapiVideo>({
|
||||||
let videoChannelId;
|
let videoChannelId;
|
||||||
if (isDefined(channel.data)) {
|
if (isDefined(channel.data)) {
|
||||||
try {
|
try {
|
||||||
const videoChannel: PayloadCreateData<VideosChannel> = {
|
|
||||||
uid: channel.data.attributes.uid,
|
|
||||||
title: channel.data.attributes.title,
|
|
||||||
subscribers: channel.data.attributes.subscribers,
|
|
||||||
};
|
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: Collections.VideosChannels,
|
collection: Collections.VideosChannels,
|
||||||
data: videoChannel,
|
data: {
|
||||||
|
uid: channel.data.attributes.uid,
|
||||||
|
title: channel.data.attributes.title,
|
||||||
|
subscribers: channel.data.attributes.subscribers,
|
||||||
|
},
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
@ -66,26 +63,24 @@ export const importFromStrapi = createStrapiImportEndpoint<Video, StapiVideo>({
|
||||||
where: { uid: { equals: channel.data.attributes.uid } },
|
where: { uid: { equals: channel.data.attributes.uid } },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.docs.length > 0) {
|
if (result.docs[0]) {
|
||||||
videoChannelId = result.docs[0].id;
|
videoChannelId = result.docs[0].id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const video: PayloadCreateData<Video> = {
|
|
||||||
uid,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
views,
|
|
||||||
likes,
|
|
||||||
gone,
|
|
||||||
source,
|
|
||||||
publishedDate: `${year}-${month}-${day}`,
|
|
||||||
channel: videoChannelId,
|
|
||||||
};
|
|
||||||
|
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: Collections.Videos,
|
collection: Collections.Videos,
|
||||||
data: video,
|
data: {
|
||||||
|
uid,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
views,
|
||||||
|
likes,
|
||||||
|
gone,
|
||||||
|
source,
|
||||||
|
publishedDate: `${year}-${month}-${day}`,
|
||||||
|
channel: videoChannelId,
|
||||||
|
},
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types";
|
import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types";
|
||||||
import { CollectionGroups, Collections, KeysTypes } from "../../constants";
|
import { CollectionGroups, Collections, KeysTypes } from "../../constants";
|
||||||
import { createGetSlugsEndpoint } from "../../endpoints/createGetSlugsEndpoint";
|
|
||||||
import { imageField } from "../../fields/imageField/imageField";
|
import { imageField } from "../../fields/imageField/imageField";
|
||||||
import { keysField } from "../../fields/keysField/keysField";
|
import { keysField } from "../../fields/keysField/keysField";
|
||||||
import { slugField } from "../../fields/slugField/slugField";
|
import { slugField } from "../../fields/slugField/slugField";
|
||||||
|
@ -43,20 +42,16 @@ export const Weapons = buildVersionedCollectionConfig({
|
||||||
],
|
],
|
||||||
group: CollectionGroups.Collections,
|
group: CollectionGroups.Collections,
|
||||||
},
|
},
|
||||||
endpoints: [
|
endpoints: [importFromStrapi, getBySlugEndpoint],
|
||||||
importFromStrapi,
|
|
||||||
createGetSlugsEndpoint(Collections.Weapons),
|
|
||||||
getBySlugEndpoint,
|
|
||||||
],
|
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: "row",
|
type: "row",
|
||||||
fields: [
|
fields: [
|
||||||
slugField({ name: fields.slug, admin: { width: "50%" } }),
|
slugField({ name: fields.slug, admin: { width: "0%" } }),
|
||||||
imageField({
|
imageField({
|
||||||
name: fields.thumbnail,
|
name: fields.thumbnail,
|
||||||
relationTo: Collections.WeaponsThumbnails,
|
relationTo: Collections.WeaponsThumbnails,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -67,13 +62,13 @@ export const Weapons = buildVersionedCollectionConfig({
|
||||||
name: fields.type,
|
name: fields.type,
|
||||||
relationTo: KeysTypes.Weapons,
|
relationTo: KeysTypes.Weapons,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: fields.group,
|
name: fields.group,
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.WeaponsGroups,
|
relationTo: Collections.WeaponsGroups,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -114,12 +109,12 @@ export const Weapons = buildVersionedCollectionConfig({
|
||||||
name: fields.appearancesTranslationsName,
|
name: fields.appearancesTranslationsName,
|
||||||
type: "text",
|
type: "text",
|
||||||
required: true,
|
required: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.appearancesTranslationsDescription,
|
name: fields.appearancesTranslationsDescription,
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -130,13 +125,13 @@ export const Weapons = buildVersionedCollectionConfig({
|
||||||
name: fields.appearancesTranslationsLevel1,
|
name: fields.appearancesTranslationsLevel1,
|
||||||
label: "Level 1",
|
label: "Level 1",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.appearancesTranslationsLevel2,
|
name: fields.appearancesTranslationsLevel2,
|
||||||
label: "Level 2",
|
label: "Level 2",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -147,13 +142,13 @@ export const Weapons = buildVersionedCollectionConfig({
|
||||||
name: fields.appearancesTranslationsLevel3,
|
name: fields.appearancesTranslationsLevel3,
|
||||||
label: "Level 3",
|
label: "Level 3",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: fields.appearancesTranslationsLevel4,
|
name: fields.appearancesTranslationsLevel4,
|
||||||
label: "Level 4",
|
label: "Level 4",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { styled } from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import payload from "payload";
|
import payload from "payload";
|
||||||
import { Collections } from "../../../constants";
|
import { Collections } from "../../../constants";
|
||||||
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
import { createStrapiImportEndpoint } from "../../../endpoints/createStrapiImportEndpoint";
|
||||||
import { Weapon, WeaponsGroup } from "../../../types/collections";
|
|
||||||
import { PayloadCreateData } from "../../../types/payload";
|
|
||||||
import { StrapiImage, StrapiLanguage } from "../../../types/strapi";
|
import { StrapiImage, StrapiLanguage } from "../../../types/strapi";
|
||||||
import { isDefined, isUndefined } from "../../../utils/asserts";
|
import { isDefined, isUndefined } from "../../../utils/asserts";
|
||||||
import { findCategory, findWeaponType, uploadStrapiImage } from "../../../utils/localApi";
|
import { findCategory, findWeaponType, uploadStrapiImage } from "../../../utils/localApi";
|
||||||
|
@ -26,7 +24,7 @@ type StrapiWeapon = {
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importFromStrapi = createStrapiImportEndpoint<Weapon, StrapiWeapon>({
|
export const importFromStrapi = createStrapiImportEndpoint<StrapiWeapon>({
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: "weapon-stories",
|
collection: "weapon-stories",
|
||||||
params: {
|
params: {
|
||||||
|
@ -46,12 +44,11 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon, StrapiWeapon>
|
||||||
let groupId: string | undefined;
|
let groupId: string | undefined;
|
||||||
if (isDefined(weapon_group.data)) {
|
if (isDefined(weapon_group.data)) {
|
||||||
try {
|
try {
|
||||||
const groupData: PayloadCreateData<WeaponsGroup> = {
|
|
||||||
slug: weapon_group.data.attributes.slug,
|
|
||||||
};
|
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: Collections.WeaponsGroups,
|
collection: Collections.WeaponsGroups,
|
||||||
data: groupData,
|
data: {
|
||||||
|
slug: weapon_group.data.attributes.slug,
|
||||||
|
},
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
@ -61,7 +58,7 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon, StrapiWeapon>
|
||||||
where: { slug: { equals: weapon_group.data.attributes.slug } },
|
where: { slug: { equals: weapon_group.data.attributes.slug } },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.docs.length > 0) {
|
if (result.docs[0]) {
|
||||||
groupId = result.docs[0].id;
|
groupId = result.docs[0].id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,43 +70,46 @@ export const importFromStrapi = createStrapiImportEndpoint<Weapon, StrapiWeapon>
|
||||||
|
|
||||||
if (isUndefined(type.data)) throw new Error("A type is required to create a Weapon");
|
if (isUndefined(type.data)) throw new Error("A type is required to create a Weapon");
|
||||||
|
|
||||||
const data: PayloadCreateData<Weapon> = {
|
await payload.create({
|
||||||
slug,
|
collection: Collections.Weapons,
|
||||||
type: await findWeaponType(type.data.attributes.slug),
|
data: {
|
||||||
group: groupId,
|
updatedBy: user.id,
|
||||||
thumbnail: thumbnailId,
|
slug,
|
||||||
appearances: await Promise.all(
|
type: await findWeaponType(type.data.attributes.slug),
|
||||||
stories.map(async ({ categories, translations }) => ({
|
group: groupId,
|
||||||
categories: await Promise.all(
|
thumbnail: thumbnailId,
|
||||||
categories.data.map(({ attributes }) => findCategory(attributes.slug))
|
appearances: await Promise.all(
|
||||||
),
|
stories.map(async ({ categories, translations }) => ({
|
||||||
translations: translations.map(
|
categories: await Promise.all(
|
||||||
({ language, description, level_1, level_2, level_3, level_4 }) => {
|
categories.data.map(({ attributes }) => findCategory(attributes.slug))
|
||||||
if (isUndefined(language.data))
|
),
|
||||||
throw new Error("A language is required to create a Weapon translation");
|
translations: translations.map(
|
||||||
const name = names.find(
|
({ language, description, level_1, level_2, level_3, level_4 }) => {
|
||||||
(name) => name.language.data?.attributes.code === language.data?.attributes.code
|
if (isUndefined(language.data))
|
||||||
)?.name;
|
throw new Error("A language is required to create a Weapon translation");
|
||||||
if (isUndefined(name))
|
const name = names.find(
|
||||||
throw new Error("A name is required to create a Weapon translation");
|
(name) => name.language.data?.attributes.code === language.data?.attributes.code
|
||||||
return {
|
)?.name;
|
||||||
language: language.data?.attributes.code,
|
if (isUndefined(name))
|
||||||
sourceLanguage: language.data?.attributes.code,
|
throw new Error("A name is required to create a Weapon translation");
|
||||||
name,
|
return {
|
||||||
description,
|
language: language.data?.attributes.code,
|
||||||
level1: level_1,
|
sourceLanguage: language.data?.attributes.code,
|
||||||
level2: level_2,
|
name,
|
||||||
level3: level_3,
|
description,
|
||||||
level4: level_4,
|
level1: level_1,
|
||||||
transcribers: [user.id],
|
level2: level_2,
|
||||||
};
|
level3: level_3,
|
||||||
}
|
level4: level_4,
|
||||||
),
|
transcribers: [user.id],
|
||||||
}))
|
};
|
||||||
),
|
}
|
||||||
};
|
),
|
||||||
|
}))
|
||||||
await payload.create({ collection: Collections.Weapons, data, user });
|
),
|
||||||
|
},
|
||||||
|
user,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { styled } from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
export const Icon = styled.div`
|
export const Icon = styled.div`
|
||||||
width: 46px;
|
width: 18px;
|
||||||
height: 46px;
|
height: 18px;
|
||||||
mask: url("/public/accords.svg");
|
mask: url("/public/accords.svg");
|
||||||
background-color: var(--theme-elevation-1000);
|
background-color: var(--theme-elevation-1000);
|
||||||
mask-size: contain;
|
mask-size: contain;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import "@fontsource/vollkorn/700.css";
|
import "@fontsource/vollkorn/700.css";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { styled } from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
export const Logo = (): JSX.Element => (
|
export const Logo = (): JSX.Element => (
|
||||||
<Container>
|
<Container>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from "react";
|
|
||||||
import { styled } from "styled-components";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import QueryString from "qs";
|
|
||||||
import { Options } from "payload/dist/collections/operations/local/find";
|
import { Options } from "payload/dist/collections/operations/local/find";
|
||||||
|
import QueryString from "qs";
|
||||||
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import styled from "styled-components";
|
||||||
import { LanguageCodes } from "../constants";
|
import { LanguageCodes } from "../constants";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import payload from "payload";
|
import payload, { GeneratedTypes } from "payload";
|
||||||
|
import { Collections } from "../constants";
|
||||||
import { CollectionEndpoint } from "../types/payload";
|
import { CollectionEndpoint } from "../types/payload";
|
||||||
|
|
||||||
export const createGetByEndpoint = <T, R>(
|
export const createGetByEndpoint = <C extends Collections, R>(
|
||||||
collection: string,
|
collection: C,
|
||||||
attribute: string,
|
attribute: string,
|
||||||
handler: (doc: T) => Promise<R> | R = (doc) => doc as unknown as R
|
handler: (doc: GeneratedTypes["collections"][C]) => Promise<R> | R
|
||||||
): CollectionEndpoint => ({
|
): CollectionEndpoint => ({
|
||||||
path: `/${attribute}/:${attribute}`,
|
path: `/${attribute}/:${attribute}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
|
@ -24,7 +25,7 @@ export const createGetByEndpoint = <T, R>(
|
||||||
where: { [attribute]: { equals: req.params[attribute] } },
|
where: { [attribute]: { equals: req.params[attribute] } },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.docs.length === 0) {
|
if (!result.docs[0]) {
|
||||||
return res.sendStatus(404);
|
return res.sendStatus(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import payload from "payload";
|
|
||||||
import { mustBeApi } from "../accesses/endpoints/mustBeApi";
|
|
||||||
import { Collections } from "../constants";
|
|
||||||
import { CollectionEndpoint } from "../types/payload";
|
|
||||||
|
|
||||||
export const createGetSlugsEndpoint = (collection: Collections): CollectionEndpoint => ({
|
|
||||||
path: "/slugs",
|
|
||||||
method: "get",
|
|
||||||
handler: async (req, res) => {
|
|
||||||
if (!mustBeApi(req)) {
|
|
||||||
return res.status(403).send({
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
message: "You are not allowed to perform this action.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let page = 1;
|
|
||||||
let totalPage = 1;
|
|
||||||
const slugs: string[] = [];
|
|
||||||
|
|
||||||
while (page <= totalPage) {
|
|
||||||
const entries = await payload.find({
|
|
||||||
collection,
|
|
||||||
page,
|
|
||||||
user: req.user,
|
|
||||||
});
|
|
||||||
|
|
||||||
entries.docs.forEach(({ slug }: { slug: string }) => slugs.push(slug));
|
|
||||||
|
|
||||||
totalPage = entries.totalPages;
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json(slugs);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -6,7 +6,7 @@ import { isDefined } from "../utils/asserts";
|
||||||
|
|
||||||
type Image = {
|
type Image = {
|
||||||
filename: string;
|
filename: string;
|
||||||
id: string | number;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createImageRegenerationEndpoint = (collection: Collections): CollectionEndpoint => ({
|
export const createImageRegenerationEndpoint = (collection: Collections): CollectionEndpoint => ({
|
||||||
|
@ -36,7 +36,7 @@ export const createImageRegenerationEndpoint = (collection: Collections): Collec
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
images.docs.map(async (image: Image) => {
|
images.docs.filter(isImage).map(async (image: Image) => {
|
||||||
try {
|
try {
|
||||||
await payload.update({
|
await payload.update({
|
||||||
collection,
|
collection,
|
||||||
|
@ -64,3 +64,9 @@ export const createImageRegenerationEndpoint = (collection: Collections): Collec
|
||||||
.json({ message: `${count} entries have been regenerated successfully.`, errors });
|
.json({ message: `${count} entries have been regenerated successfully.`, errors });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isImage = (item: Object): item is Image => {
|
||||||
|
if (!("id" in item) || typeof item.id !== "string") return false;
|
||||||
|
if (!("filename" in item) || typeof item.filename !== "string") return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import payload from "payload";
|
import payload, { GeneratedTypes } from "payload";
|
||||||
|
import { BasePayload } from "payload/dist/payload";
|
||||||
import QueryString from "qs";
|
import QueryString from "qs";
|
||||||
|
import { Collections } from "../constants";
|
||||||
import { Recorder } from "../types/collections";
|
import { Recorder } from "../types/collections";
|
||||||
import { CollectionEndpoint, PayloadCreateData } from "../types/payload";
|
import { CollectionEndpoint } from "../types/payload";
|
||||||
import { isDefined } from "../utils/asserts";
|
import { isDefined } from "../utils/asserts";
|
||||||
|
|
||||||
export const getAllStrapiEntries = async <T>(
|
export const getAllStrapiEntries = async (
|
||||||
collectionSlug: string,
|
collectionSlug: string,
|
||||||
params: Object
|
params: Object
|
||||||
): Promise<T[]> => {
|
): Promise<any[]> => {
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let totalPage = 1;
|
let totalPage = 1;
|
||||||
const result: T[] = [];
|
const result: any[] = [];
|
||||||
|
|
||||||
while (page <= totalPage) {
|
while (page <= totalPage) {
|
||||||
const paramsWithPagination = QueryString.stringify({
|
const paramsWithPagination = QueryString.stringify({
|
||||||
|
@ -30,24 +32,27 @@ export const getAllStrapiEntries = async <T>(
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Params<T, S> = {
|
type Params<S> = {
|
||||||
strapi: {
|
strapi: {
|
||||||
collection: string;
|
collection: string;
|
||||||
params: any;
|
params: any;
|
||||||
};
|
};
|
||||||
payload: {
|
payload: {
|
||||||
collection: string;
|
collection: Collections;
|
||||||
import?: (strapiObject: S, user: any) => Promise<void>;
|
import?: (strapiObject: S, user: any) => Promise<void>;
|
||||||
convert?: (strapiObject: S, user: any) => PayloadCreateData<T>;
|
convert?: (
|
||||||
|
strapiObject: S,
|
||||||
|
user: any
|
||||||
|
) => Parameters<BasePayload<GeneratedTypes>["create"]>[0]["data"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importStrapiEntries = async <T, S>({
|
export const importStrapiEntries = async <S>({
|
||||||
strapi: strapiParams,
|
strapi: strapiParams,
|
||||||
payload: payloadParams,
|
payload: payloadParams,
|
||||||
user,
|
user,
|
||||||
}: Params<T, S> & { user: Recorder }) => {
|
}: Params<S> & { user: Recorder }) => {
|
||||||
const entries = await getAllStrapiEntries<any>(strapiParams.collection, strapiParams.params);
|
const entries = await getAllStrapiEntries(strapiParams.collection, strapiParams.params);
|
||||||
|
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
@ -77,7 +82,7 @@ export const importStrapiEntries = async <T, S>({
|
||||||
return { count: entries.length, errors };
|
return { count: entries.length, errors };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createStrapiImportEndpoint = <T, S>(params: Params<T, S>): CollectionEndpoint => ({
|
export const createStrapiImportEndpoint = <S>(params: Params<S>): CollectionEndpoint => ({
|
||||||
method: "post",
|
method: "post",
|
||||||
path: "/strapi",
|
path: "/strapi",
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import payload from "payload";
|
import payload from "payload";
|
||||||
import { FieldBase } from "payload/dist/fields/config/types";
|
import { FieldBase } from "payload/dist/fields/config/types";
|
||||||
import { RelationshipField, Where } from "payload/types";
|
import { RelationshipField, Where } from "payload/types";
|
||||||
|
import { Collections } from "../../constants";
|
||||||
import { isNotEmpty } from "../../utils/asserts";
|
import { isNotEmpty } from "../../utils/asserts";
|
||||||
|
|
||||||
type BackPropagationField = FieldBase & {
|
type BackPropagationField = FieldBase & {
|
||||||
where: (data: any) => Where;
|
where: (data: any) => Where;
|
||||||
relationTo: string;
|
relationTo: Collections;
|
||||||
hasMany?: boolean;
|
hasMany?: boolean;
|
||||||
};
|
};
|
||||||
export const backPropagationField = ({
|
export const backPropagationField = ({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Props } from "payload/components/views/Cell";
|
import { Props } from "payload/components/views/Cell";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { styled } from "styled-components";
|
import styled from "styled-components";
|
||||||
import { isUndefined } from "../../utils/asserts";
|
import { isUndefined } from "../../utils/asserts";
|
||||||
|
|
||||||
const Image = styled.img`
|
const Image = styled.img`
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { Language } from "../../types/collections";
|
||||||
import { isDefined } from "../../utils/asserts";
|
import { isDefined } from "../../utils/asserts";
|
||||||
import { formatLanguageCode, shortenEllipsis } from "../../utils/string";
|
import { formatLanguageCode, shortenEllipsis } from "../../utils/string";
|
||||||
import { Language } from "../../types/collections";
|
|
||||||
import { styled } from "styled-components";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
language?: Language | string;
|
language?: Language | string;
|
||||||
|
|
|
@ -28,7 +28,7 @@ const languageField: Field = {
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Languages,
|
relationTo: Collections.Languages,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const sourceLanguageField: Field = {
|
const sourceLanguageField: Field = {
|
||||||
|
@ -36,7 +36,7 @@ const sourceLanguageField: Field = {
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: Collections.Languages,
|
relationTo: Collections.Languages,
|
||||||
required: true,
|
required: true,
|
||||||
admin: { allowCreate: false, width: "50%" },
|
admin: { allowCreate: false, width: "0%" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const creditFields: Field = {
|
const creditFields: Field = {
|
||||||
|
@ -64,7 +64,7 @@ const creditFields: Field = {
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData.language === siblingData.sourceLanguage,
|
condition: (_, siblingData) => siblingData.language === siblingData.sourceLanguage,
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
validate: (count, { siblingData }) => {
|
validate: (count, { siblingData }) => {
|
||||||
if (siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage]) {
|
if (siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage]) {
|
||||||
|
@ -95,7 +95,7 @@ const creditFields: Field = {
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) =>
|
condition: (_, siblingData) =>
|
||||||
siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage],
|
siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage],
|
||||||
width: "50%",
|
width: "0%",
|
||||||
},
|
},
|
||||||
validate: (count, { siblingData }) => {
|
validate: (count, { siblingData }) => {
|
||||||
if (siblingData[fieldsNames.language] === siblingData[fieldsNames.sourceLanguage]) {
|
if (siblingData[fieldsNames.language] === siblingData[fieldsNames.sourceLanguage]) {
|
||||||
|
@ -114,7 +114,7 @@ const creditFields: Field = {
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
relationTo: "recorders",
|
relationTo: "recorders",
|
||||||
hasMany: true,
|
hasMany: true,
|
||||||
admin: { width: "50%" },
|
admin: { width: "0%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import { webpackBundler } from "@payloadcms/bundler-webpack";
|
||||||
|
import { mongooseAdapter } from "@payloadcms/db-mongodb";
|
||||||
|
import { BlocksFeature, lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { buildConfig } from "payload/config";
|
import { buildConfig } from "payload/config";
|
||||||
import { ChronologyEras } from "./collections/ChronologyEras/ChronologyEras";
|
import { ChronologyEras } from "./collections/ChronologyEras/ChronologyEras";
|
||||||
import { ChronologyItems } from "./collections/ChronologyItems/ChronologyItems";
|
import { ChronologyItems } from "./collections/ChronologyItems/ChronologyItems";
|
||||||
|
import { transcriptBlock } from "./collections/Contents/Blocks/transcriptBlock";
|
||||||
import { Contents } from "./collections/Contents/Contents";
|
import { Contents } from "./collections/Contents/Contents";
|
||||||
import { ContentsFolders } from "./collections/ContentsFolders/ContentsFolders";
|
import { ContentsFolders } from "./collections/ContentsFolders/ContentsFolders";
|
||||||
import { ContentsThumbnails } from "./collections/ContentsThumbnails/ContentsThumbnails";
|
import { ContentsThumbnails } from "./collections/ContentsThumbnails/ContentsThumbnails";
|
||||||
|
@ -25,7 +29,6 @@ import { WeaponsThumbnails } from "./collections/WeaponsThumbnails/WeaponsThumbn
|
||||||
import { Icon } from "./components/Icon";
|
import { Icon } from "./components/Icon";
|
||||||
import { Logo } from "./components/Logo";
|
import { Logo } from "./components/Logo";
|
||||||
import { Collections } from "./constants";
|
import { Collections } from "./constants";
|
||||||
import { payloadGridView } from "./plugins/payload-grid-view";
|
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
serverURL: process.env.PAYLOAD_URI,
|
serverURL: process.env.PAYLOAD_URI,
|
||||||
|
@ -38,7 +41,14 @@ export default buildConfig({
|
||||||
titleSuffix: "- Accord’s Library",
|
titleSuffix: "- Accord’s Library",
|
||||||
},
|
},
|
||||||
css: path.resolve(__dirname, "styles.scss"),
|
css: path.resolve(__dirname, "styles.scss"),
|
||||||
|
bundler: webpackBundler(),
|
||||||
},
|
},
|
||||||
|
editor: lexicalEditor({
|
||||||
|
features: ({ defaultFeatures }) => [
|
||||||
|
...defaultFeatures,
|
||||||
|
BlocksFeature({ blocks: [transcriptBlock] }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
collections: [
|
collections: [
|
||||||
LibraryItems,
|
LibraryItems,
|
||||||
Contents,
|
Contents,
|
||||||
|
@ -63,6 +73,9 @@ export default buildConfig({
|
||||||
Recorders,
|
Recorders,
|
||||||
Keys,
|
Keys,
|
||||||
],
|
],
|
||||||
|
db: mongooseAdapter({
|
||||||
|
url: process.env.MONGODB_URI ?? "mongodb://mongo:27017/payload",
|
||||||
|
}),
|
||||||
globals: [],
|
globals: [],
|
||||||
telemetry: false,
|
telemetry: false,
|
||||||
typescript: {
|
typescript: {
|
||||||
|
@ -71,5 +84,4 @@ export default buildConfig({
|
||||||
graphQL: {
|
graphQL: {
|
||||||
disable: true,
|
disable: true,
|
||||||
},
|
},
|
||||||
plugins: [payloadGridView],
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
.grid {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
|
|
||||||
> .grid__header {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
display: flex;
|
|
||||||
gap: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .grid__cells {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 1rem;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
||||||
|
|
||||||
> .grid__cells__cell {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 1fr;
|
|
||||||
background-color: var(--theme-elevation-50);
|
|
||||||
border: 1px solid var(--theme-elevation-100);
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> .grid__cells__cell__filename {
|
|
||||||
position: relative;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
|
|
||||||
.thumbnail {
|
|
||||||
> img {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
object-fit: contain;
|
|
||||||
background-size: 9% 9%;
|
|
||||||
background-position: center;
|
|
||||||
background-image: radial-gradient(
|
|
||||||
circle,
|
|
||||||
var(--theme-elevation-100) 1px,
|
|
||||||
var(--theme-elevation-0) 1px
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .grid__cells__cell__selector {
|
|
||||||
position: absolute;
|
|
||||||
left: 0.75rem;
|
|
||||||
top: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .grid__cells__cell__info {
|
|
||||||
display: grid;
|
|
||||||
line-height: 1.5;
|
|
||||||
padding: 1rem;
|
|
||||||
gap: 0.5rem;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
> .grid__cells__cell__title {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .grid__cells__cell__others {
|
|
||||||
display: grid;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--theme-elevation-600);
|
|
||||||
width: 100%;
|
|
||||||
font-size: 90%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
import { useTableColumns } from "payload/dist/admin/components/elements/TableColumns";
|
|
||||||
import React, { Fragment } from "react";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
|
|
||||||
import "payload/dist/admin/components/elements/Table/index.scss";
|
|
||||||
import { Column } from "payload/dist/admin/components/elements/Table/types";
|
|
||||||
import Thumbnail from "payload/dist/admin/components/elements/Thumbnail";
|
|
||||||
import { SanitizedCollectionConfig } from "payload/types";
|
|
||||||
import "./index.scss";
|
|
||||||
|
|
||||||
const baseClass = "grid";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
data: any[];
|
|
||||||
collection: SanitizedCollectionConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fieldNames = {
|
|
||||||
filename: "filename",
|
|
||||||
select: "_select",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Grid: React.FC<Props> = ({ data, collection }) => {
|
|
||||||
const { columns: columnsFromContext } = useTableColumns();
|
|
||||||
|
|
||||||
const fields = columnsFromContext;
|
|
||||||
const otherFields = fields?.filter(
|
|
||||||
(col) => col.active && ![fieldNames.filename, fieldNames.select].includes(col.accessor)
|
|
||||||
);
|
|
||||||
|
|
||||||
const filenameField = fields.find((col) => col.accessor === fieldNames.filename);
|
|
||||||
const selectorField = fields.find((col) => col.accessor === fieldNames.select);
|
|
||||||
|
|
||||||
const headerColumns = fields
|
|
||||||
.sort((a, b) => {
|
|
||||||
const sortingValue = (value: Column) => {
|
|
||||||
switch (value.accessor) {
|
|
||||||
case fieldNames.select:
|
|
||||||
return 2;
|
|
||||||
case fieldNames.filename:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return sortingValue(b) - sortingValue(a);
|
|
||||||
})
|
|
||||||
.filter(({ active, accessor }) => active || accessor === fieldNames.filename);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={baseClass}>
|
|
||||||
<div className={`${baseClass}__header`}>
|
|
||||||
{headerColumns.map((col, index) => (
|
|
||||||
<div key={index} id={`heading-${col.accessor}`}>
|
|
||||||
{col.components.Heading}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className={`${baseClass}__cells`}>
|
|
||||||
{data &&
|
|
||||||
data.map((gridCell, cellIndex) => (
|
|
||||||
<div key={cellIndex} className={`${baseClass}__cells__cell`}>
|
|
||||||
{filenameField && (
|
|
||||||
<Link
|
|
||||||
className={`${baseClass}__cells__cell__filename`}
|
|
||||||
to={`${collection.slug}/${gridCell.id}`}>
|
|
||||||
<Thumbnail collection={collection} doc={gridCell} />
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
{selectorField && (
|
|
||||||
<div className={`${baseClass}__cells__cell__selector`}>
|
|
||||||
{selectorField.components.renderCell(gridCell, gridCell[selectorField.accessor])}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className={`${baseClass}__cells__cell__info`}>
|
|
||||||
{filenameField && (
|
|
||||||
<Link
|
|
||||||
className={`${baseClass}__cells__cell__title`}
|
|
||||||
to={`${collection.slug}/${gridCell.id}`}>
|
|
||||||
{String(gridCell[filenameField.accessor])}
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
{otherFields.length > 0 && (
|
|
||||||
<div className={`${baseClass}__cells__cell__others`}>
|
|
||||||
{otherFields.map((col, colIndex) => (
|
|
||||||
<Fragment key={colIndex}>
|
|
||||||
{col.components.renderCell(gridCell, gridCell[col.accessor])}
|
|
||||||
</Fragment>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Grid;
|
|
|
@ -1,202 +0,0 @@
|
||||||
import { useWindowInfo } from "@faceless-ui/window-info";
|
|
||||||
import Button from "payload/dist/admin/components/elements/Button";
|
|
||||||
import DeleteMany from "payload/dist/admin/components/elements/DeleteMany";
|
|
||||||
import EditMany from "payload/dist/admin/components/elements/EditMany";
|
|
||||||
import Eyebrow from "payload/dist/admin/components/elements/Eyebrow";
|
|
||||||
import { Gutter } from "payload/dist/admin/components/elements/Gutter";
|
|
||||||
import ListSelection from "payload/dist/admin/components/elements/ListSelection";
|
|
||||||
import Paginator from "payload/dist/admin/components/elements/Paginator";
|
|
||||||
import PerPage from "payload/dist/admin/components/elements/PerPage";
|
|
||||||
import Pill from "payload/dist/admin/components/elements/Pill";
|
|
||||||
import PublishMany from "payload/dist/admin/components/elements/PublishMany";
|
|
||||||
import { StaggeredShimmers } from "payload/dist/admin/components/elements/ShimmerEffect";
|
|
||||||
import { Table } from "payload/dist/admin/components/elements/Table";
|
|
||||||
import UnpublishMany from "payload/dist/admin/components/elements/UnpublishMany";
|
|
||||||
import ViewDescription from "payload/dist/admin/components/elements/ViewDescription";
|
|
||||||
import Meta from "payload/dist/admin/components/utilities/Meta";
|
|
||||||
import { RelationshipProvider } from "payload/dist/admin/components/views/collections/List/RelationshipProvider";
|
|
||||||
import { SelectionProvider } from "payload/dist/admin/components/views/collections/List/SelectionProvider";
|
|
||||||
import { Props } from "payload/dist/admin/components/views/collections/List/types";
|
|
||||||
import formatFilesize from "payload/dist/uploads/formatFilesize";
|
|
||||||
import { getTranslation } from "payload/dist/utilities/getTranslation";
|
|
||||||
import React, { Fragment, useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import Grid from "../Grid";
|
|
||||||
import ListControls, { ViewMode } from "../ListControls";
|
|
||||||
|
|
||||||
const baseClass = "collection-list";
|
|
||||||
|
|
||||||
export type UploadsGridViewOptions = {
|
|
||||||
list?: boolean;
|
|
||||||
grid?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DefaultList =
|
|
||||||
(options: UploadsGridViewOptions) =>
|
|
||||||
(props: Props): JSX.Element => {
|
|
||||||
const {
|
|
||||||
collection,
|
|
||||||
collection: {
|
|
||||||
labels: { singular: singularLabel, plural: pluralLabel },
|
|
||||||
admin: {
|
|
||||||
description,
|
|
||||||
components: { BeforeList, BeforeListTable, AfterListTable, AfterList } = {},
|
|
||||||
} = {},
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
newDocumentURL,
|
|
||||||
limit,
|
|
||||||
hasCreatePermission,
|
|
||||||
disableEyebrow,
|
|
||||||
modifySearchParams,
|
|
||||||
handleSortChange,
|
|
||||||
handleWhereChange,
|
|
||||||
handlePageChange,
|
|
||||||
handlePerPageChange,
|
|
||||||
customHeader,
|
|
||||||
resetParams,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const [viewMode, setViewMode] = useState<ViewMode>(options.grid === true ? "grid" : "list");
|
|
||||||
|
|
||||||
const {
|
|
||||||
breakpoints: { s: smallBreak },
|
|
||||||
} = useWindowInfo();
|
|
||||||
const { t, i18n } = useTranslation("general");
|
|
||||||
let formattedDocs = data.docs || [];
|
|
||||||
|
|
||||||
if (collection.upload) {
|
|
||||||
formattedDocs = formattedDocs?.map((doc) => {
|
|
||||||
return {
|
|
||||||
...doc,
|
|
||||||
filesize: formatFilesize(doc.filesize),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={baseClass}>
|
|
||||||
{Array.isArray(BeforeList) &&
|
|
||||||
BeforeList.map((Component, i) => <Component key={i} {...props} />)}
|
|
||||||
|
|
||||||
<Meta title={getTranslation(collection.labels.plural, i18n)} />
|
|
||||||
<SelectionProvider docs={data.docs} totalDocs={data.totalDocs}>
|
|
||||||
{!disableEyebrow && <Eyebrow />}
|
|
||||||
<Gutter className={`${baseClass}__wrap`}>
|
|
||||||
<header className={`${baseClass}__header`}>
|
|
||||||
{customHeader && customHeader}
|
|
||||||
{!customHeader && (
|
|
||||||
<Fragment>
|
|
||||||
<h1>{getTranslation(pluralLabel, i18n)}</h1>
|
|
||||||
{hasCreatePermission && (
|
|
||||||
<Pill
|
|
||||||
to={newDocumentURL}
|
|
||||||
aria-label={t("createNewLabel", {
|
|
||||||
label: getTranslation(singularLabel, i18n),
|
|
||||||
})}>
|
|
||||||
{t("createNew")}
|
|
||||||
</Pill>
|
|
||||||
)}
|
|
||||||
{!smallBreak && (
|
|
||||||
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
|
|
||||||
)}
|
|
||||||
{description && (
|
|
||||||
<div className={`${baseClass}__sub-header`}>
|
|
||||||
<ViewDescription description={description} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</header>
|
|
||||||
<ListControls
|
|
||||||
collection={collection}
|
|
||||||
modifySearchQuery={modifySearchParams}
|
|
||||||
handleSortChange={handleSortChange}
|
|
||||||
handleWhereChange={handleWhereChange}
|
|
||||||
handleViewModeChange={(newViewMode) => setViewMode(newViewMode)}
|
|
||||||
resetParams={resetParams}
|
|
||||||
viewMode={viewMode}
|
|
||||||
showViewModeToggle={options.list === true && options.grid === true}
|
|
||||||
/>
|
|
||||||
{Array.isArray(BeforeListTable) &&
|
|
||||||
BeforeListTable.map((Component, i) => <Component key={i} {...props} />)}
|
|
||||||
{!data.docs && (
|
|
||||||
<StaggeredShimmers
|
|
||||||
className={[`${baseClass}__shimmer`, `${baseClass}__shimmer--rows`].join(" ")}
|
|
||||||
count={6}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{data.docs && data.docs.length > 0 && (
|
|
||||||
<RelationshipProvider>
|
|
||||||
{viewMode === "grid" ? (
|
|
||||||
<Grid data={formattedDocs} collection={collection} />
|
|
||||||
) : (
|
|
||||||
<Table data={formattedDocs} />
|
|
||||||
)}
|
|
||||||
</RelationshipProvider>
|
|
||||||
)}
|
|
||||||
{data.docs && data.docs.length === 0 && (
|
|
||||||
<div className={`${baseClass}__no-results`}>
|
|
||||||
<p>{t("noResults", { label: getTranslation(pluralLabel, i18n) })}</p>
|
|
||||||
{hasCreatePermission && newDocumentURL && (
|
|
||||||
<Button el="link" to={newDocumentURL}>
|
|
||||||
{t("createNewLabel", { label: getTranslation(singularLabel, i18n) })}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{Array.isArray(AfterListTable) &&
|
|
||||||
AfterListTable.map((Component, i) => <Component key={i} {...props} />)}
|
|
||||||
|
|
||||||
<div className={`${baseClass}__page-controls`}>
|
|
||||||
<Paginator
|
|
||||||
limit={data.limit}
|
|
||||||
totalPages={data.totalPages}
|
|
||||||
page={data.page}
|
|
||||||
hasPrevPage={data.hasPrevPage}
|
|
||||||
hasNextPage={data.hasNextPage}
|
|
||||||
prevPage={data.prevPage ?? undefined}
|
|
||||||
nextPage={data.nextPage ?? undefined}
|
|
||||||
numberOfNeighbors={1}
|
|
||||||
disableHistoryChange={modifySearchParams === false}
|
|
||||||
onChange={handlePageChange}
|
|
||||||
/>
|
|
||||||
{data?.totalDocs > 0 && (
|
|
||||||
<Fragment>
|
|
||||||
<div className={`${baseClass}__page-info`}>
|
|
||||||
{data.page ?? 1 * data.limit - (data.limit - 1)}-
|
|
||||||
{data.totalPages > 1 && data.totalPages !== data.page
|
|
||||||
? data.limit * (data.page ?? 1)
|
|
||||||
: data.totalDocs}{" "}
|
|
||||||
{t("of")} {data.totalDocs}
|
|
||||||
</div>
|
|
||||||
<PerPage
|
|
||||||
limits={collection?.admin?.pagination?.limits}
|
|
||||||
limit={limit}
|
|
||||||
modifySearchParams={modifySearchParams}
|
|
||||||
handleChange={handlePerPageChange}
|
|
||||||
resetPage={data.totalDocs <= data.pagingCounter}
|
|
||||||
/>
|
|
||||||
<div className={`${baseClass}__list-selection`}>
|
|
||||||
{smallBreak && (
|
|
||||||
<Fragment>
|
|
||||||
<ListSelection label={getTranslation(collection.labels.plural, i18n)} />
|
|
||||||
<div className={`${baseClass}__list-selection-actions`}>
|
|
||||||
<EditMany collection={collection} resetParams={resetParams} />
|
|
||||||
<PublishMany collection={collection} resetParams={resetParams} />
|
|
||||||
<UnpublishMany collection={collection} resetParams={resetParams} />
|
|
||||||
<DeleteMany collection={collection} resetParams={resetParams} />
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
</SelectionProvider>
|
|
||||||
{Array.isArray(AfterList) &&
|
|
||||||
AfterList.map((Component, i) => <Component key={i} {...props} />)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,228 +0,0 @@
|
||||||
import { useWindowInfo } from "@faceless-ui/window-info";
|
|
||||||
import Button from "payload/dist/admin/components/elements/Button";
|
|
||||||
import ColumnSelector from "payload/dist/admin/components/elements/ColumnSelector";
|
|
||||||
import DeleteMany from "payload/dist/admin/components/elements/DeleteMany";
|
|
||||||
import EditMany from "payload/dist/admin/components/elements/EditMany";
|
|
||||||
import { getTextFieldsToBeSearched } from "payload/dist/admin/components/elements/ListControls/getTextFieldsToBeSearched";
|
|
||||||
import { Props } from "payload/dist/admin/components/elements/ListControls/types";
|
|
||||||
import Pill from "payload/dist/admin/components/elements/Pill";
|
|
||||||
import PublishMany from "payload/dist/admin/components/elements/PublishMany";
|
|
||||||
import SearchFilter from "payload/dist/admin/components/elements/SearchFilter";
|
|
||||||
import SortComplex from "payload/dist/admin/components/elements/SortComplex";
|
|
||||||
import UnpublishMany from "payload/dist/admin/components/elements/UnpublishMany";
|
|
||||||
import WhereBuilder from "payload/dist/admin/components/elements/WhereBuilder";
|
|
||||||
import validateWhereQuery from "payload/dist/admin/components/elements/WhereBuilder/validateWhereQuery";
|
|
||||||
import Chevron from "payload/dist/admin/components/icons/Chevron";
|
|
||||||
import { useSearchParams } from "payload/dist/admin/components/utilities/SearchParams";
|
|
||||||
import { SanitizedCollectionConfig } from "payload/dist/collections/config/types";
|
|
||||||
import { fieldAffectsData } from "payload/dist/fields/config/types";
|
|
||||||
import flattenFields from "payload/dist/utilities/flattenTopLevelFields";
|
|
||||||
import { getTranslation } from "payload/dist/utilities/getTranslation";
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import AnimateHeight from "react-animate-height";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
const baseClass = "list-controls";
|
|
||||||
|
|
||||||
export type ViewMode = "grid" | "list";
|
|
||||||
|
|
||||||
const getUseAsTitle = (collection: SanitizedCollectionConfig) => {
|
|
||||||
const {
|
|
||||||
admin: { useAsTitle },
|
|
||||||
fields,
|
|
||||||
} = collection;
|
|
||||||
|
|
||||||
const topLevelFields = flattenFields(fields);
|
|
||||||
return topLevelFields.find((field) => fieldAffectsData(field) && field.name === useAsTitle);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ListControls component is used to render the controls (search, filter, where)
|
|
||||||
* for a collection's list view. You can find those directly above the table which lists
|
|
||||||
* the collection's documents.
|
|
||||||
*/
|
|
||||||
const ListControls: React.FC<
|
|
||||||
Props & {
|
|
||||||
viewMode: ViewMode;
|
|
||||||
handleViewModeChange: (newMode: ViewMode) => void;
|
|
||||||
showViewModeToggle: boolean;
|
|
||||||
}
|
|
||||||
> = (props) => {
|
|
||||||
const {
|
|
||||||
collection,
|
|
||||||
enableColumns = true,
|
|
||||||
enableSort = false,
|
|
||||||
handleSortChange,
|
|
||||||
handleWhereChange,
|
|
||||||
modifySearchQuery = true,
|
|
||||||
resetParams = () => undefined,
|
|
||||||
viewMode,
|
|
||||||
handleViewModeChange,
|
|
||||||
collection: {
|
|
||||||
fields,
|
|
||||||
admin: { listSearchableFields },
|
|
||||||
},
|
|
||||||
showViewModeToggle,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const params = useSearchParams();
|
|
||||||
const shouldInitializeWhereOpened = validateWhereQuery(params?.where);
|
|
||||||
|
|
||||||
const [titleField, setTitleField] = useState(getUseAsTitle(collection));
|
|
||||||
useEffect(() => {
|
|
||||||
setTitleField(getUseAsTitle(collection));
|
|
||||||
}, [collection]);
|
|
||||||
|
|
||||||
const [textFieldsToBeSearched] = useState(
|
|
||||||
getTextFieldsToBeSearched(listSearchableFields, fields)
|
|
||||||
);
|
|
||||||
const [visibleDrawer, setVisibleDrawer] = useState<"where" | "sort" | "columns" | undefined>(
|
|
||||||
shouldInitializeWhereOpened ? "where" : undefined
|
|
||||||
);
|
|
||||||
const { t, i18n } = useTranslation("general");
|
|
||||||
const {
|
|
||||||
breakpoints: { s: smallBreak },
|
|
||||||
} = useWindowInfo();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={baseClass}>
|
|
||||||
<div className={`${baseClass}__wrap`}>
|
|
||||||
<SearchFilter
|
|
||||||
fieldName={titleField && fieldAffectsData(titleField) ? titleField.name : undefined}
|
|
||||||
handleChange={handleWhereChange}
|
|
||||||
modifySearchQuery={modifySearchQuery}
|
|
||||||
fieldLabel={
|
|
||||||
titleField && fieldAffectsData(titleField)
|
|
||||||
? getTranslation(String(titleField.label ?? titleField.name), i18n)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
listSearchableFields={textFieldsToBeSearched}
|
|
||||||
/>
|
|
||||||
<div className={`${baseClass}__buttons`}>
|
|
||||||
<div className={`${baseClass}__buttons-wrap`}>
|
|
||||||
{!smallBreak && (
|
|
||||||
<React.Fragment>
|
|
||||||
<EditMany collection={collection} resetParams={resetParams} />
|
|
||||||
<PublishMany collection={collection} resetParams={resetParams} />
|
|
||||||
<UnpublishMany collection={collection} resetParams={resetParams} />
|
|
||||||
<DeleteMany collection={collection} resetParams={resetParams} />
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
{enableColumns && (
|
|
||||||
<Pill
|
|
||||||
pillStyle="light"
|
|
||||||
className={`${baseClass}__toggle-columns ${
|
|
||||||
visibleDrawer === "columns" ? `${baseClass}__buttons-active` : ""
|
|
||||||
}`}
|
|
||||||
onClick={() =>
|
|
||||||
setVisibleDrawer(visibleDrawer !== "columns" ? "columns" : undefined)
|
|
||||||
}
|
|
||||||
aria-expanded={visibleDrawer === "columns"}
|
|
||||||
aria-controls={`${baseClass}-columns`}
|
|
||||||
icon={<Chevron />}>
|
|
||||||
{t("columns")}
|
|
||||||
</Pill>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Pill
|
|
||||||
pillStyle="light"
|
|
||||||
className={`${baseClass}__toggle-where ${
|
|
||||||
visibleDrawer === "where" ? `${baseClass}__buttons-active` : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setVisibleDrawer(visibleDrawer !== "where" ? "where" : undefined)}
|
|
||||||
aria-expanded={visibleDrawer === "where"}
|
|
||||||
aria-controls={`${baseClass}-where`}
|
|
||||||
icon={<Chevron />}>
|
|
||||||
{t("filters")}
|
|
||||||
</Pill>
|
|
||||||
{enableSort && (
|
|
||||||
<Button
|
|
||||||
className={`${baseClass}__toggle-sort`}
|
|
||||||
buttonStyle={visibleDrawer === "sort" ? undefined : "secondary"}
|
|
||||||
onClick={() => setVisibleDrawer(visibleDrawer !== "sort" ? "sort" : undefined)}
|
|
||||||
aria-expanded={visibleDrawer === "sort"}
|
|
||||||
aria-controls={`${baseClass}-sort`}
|
|
||||||
icon="chevron"
|
|
||||||
iconStyle="none">
|
|
||||||
{t("sort")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{showViewModeToggle && (
|
|
||||||
<div style={{ marginLeft: 10 }}>
|
|
||||||
<svg
|
|
||||||
onClick={() => handleViewModeChange("list")}
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
color:
|
|
||||||
viewMode === "list"
|
|
||||||
? "var(--theme-elevation-1000)"
|
|
||||||
: "var(--theme-elevation-500)",
|
|
||||||
}}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
height="32"
|
|
||||||
width="28">
|
|
||||||
<path
|
|
||||||
fill="currentColor"
|
|
||||||
d="M333-242h432.5q12 0 22-10t10-22v-100.5H333V-242ZM162.5-586h145v-132h-113q-12 0-22 10t-10 22v100Zm0 187h145v-161.5h-145V-399Zm32 157h113v-132.5h-145V-274q0 12 10 22t22 10ZM333-399h464.5v-161.5H333V-399Zm0-187h464.5v-100q0-12-10-22t-22-10H333v132ZM194.28-216.5q-24.218 0-40.749-16.531Q137-249.562 137-273.802v-412.396q0-24.24 16.531-40.771Q170.062-743.5 194.28-743.5h571.44q24.218 0 40.749 16.531Q823-710.438 823-686.198v412.396q0 24.24-16.531 40.771Q789.938-216.5 765.72-216.5H194.28Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
onClick={() => handleViewModeChange("grid")}
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
color:
|
|
||||||
viewMode === "grid"
|
|
||||||
? "var(--theme-elevation-1000)"
|
|
||||||
: "var(--theme-elevation-500)",
|
|
||||||
}}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 -960 960 960"
|
|
||||||
height="28"
|
|
||||||
width="28">
|
|
||||||
<path
|
|
||||||
fill="currentColor"
|
|
||||||
d="M176.5-519v-264.5h265V-519h-265Zm0 342.5v-265h265v265h-265ZM519-519v-264.5h264.5V-519H519Zm0 342.5v-265h264.5v265H519Zm-317-368h214V-758H202v213.5Zm342.5 0H758V-758H544.5v213.5Zm0 342.5H758v-214H544.5v214ZM202-202h214v-214H202v214Zm342.5-342.5Zm0 128.5ZM416-416Zm0-128.5Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{enableColumns && (
|
|
||||||
<AnimateHeight
|
|
||||||
className={`${baseClass}__columns`}
|
|
||||||
height={visibleDrawer === "columns" ? "auto" : 0}
|
|
||||||
id={`${baseClass}-columns`}>
|
|
||||||
<ColumnSelector collection={collection} />
|
|
||||||
</AnimateHeight>
|
|
||||||
)}
|
|
||||||
<AnimateHeight
|
|
||||||
className={`${baseClass}__where`}
|
|
||||||
height={visibleDrawer === "where" ? "auto" : 0}
|
|
||||||
id={`${baseClass}-where`}>
|
|
||||||
<WhereBuilder
|
|
||||||
collection={collection}
|
|
||||||
modifySearchQuery={modifySearchQuery}
|
|
||||||
handleChange={handleWhereChange}
|
|
||||||
/>
|
|
||||||
</AnimateHeight>
|
|
||||||
{enableSort && (
|
|
||||||
<AnimateHeight
|
|
||||||
className={`${baseClass}__sort`}
|
|
||||||
height={visibleDrawer === "sort" ? "auto" : 0}
|
|
||||||
id={`${baseClass}-sort`}>
|
|
||||||
<SortComplex
|
|
||||||
modifySearchQuery={modifySearchQuery}
|
|
||||||
collection={collection}
|
|
||||||
handleChange={handleSortChange}
|
|
||||||
/>
|
|
||||||
</AnimateHeight>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ListControls;
|
|
|
@ -1,53 +0,0 @@
|
||||||
import { Plugin } from "payload/config";
|
|
||||||
import { CollectionAdminOptions } from "payload/dist/collections/config/types";
|
|
||||||
import { CollectionConfig } from "payload/types";
|
|
||||||
import { DefaultList, UploadsGridViewOptions } from "./components/List";
|
|
||||||
|
|
||||||
type Components = Required<CollectionAdminOptions>["components"];
|
|
||||||
type ViewsComponents = Required<Required<CollectionAdminOptions>["components"]>["views"];
|
|
||||||
|
|
||||||
type Options = {
|
|
||||||
isUploadEnabled: boolean;
|
|
||||||
gridView: UploadsGridViewOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CollectionConfigWithGridView = CollectionConfig & {
|
|
||||||
custom?: { gridView?: UploadsGridViewOptions };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const payloadGridView: Plugin = ({ collections, ...others }) => ({
|
|
||||||
collections: collections?.map(handleCollection),
|
|
||||||
...others,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCollection = ({
|
|
||||||
admin,
|
|
||||||
...others
|
|
||||||
}: CollectionConfigWithGridView): CollectionConfig => ({
|
|
||||||
...others,
|
|
||||||
admin: handleAdmin(admin, {
|
|
||||||
isUploadEnabled: others.upload !== undefined,
|
|
||||||
gridView: others.custom?.gridView ?? { grid: true, list: true },
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleAdmin = (
|
|
||||||
{ components, ...others }: CollectionAdminOptions = {},
|
|
||||||
options: Options
|
|
||||||
): CollectionAdminOptions => ({
|
|
||||||
...others,
|
|
||||||
components: handleComponents(components, options),
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleComponents = ({ views, ...others }: Components = {}, options: Options): Components => ({
|
|
||||||
...others,
|
|
||||||
views: handleViewsComponents(views, options),
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleViewsComponents = (
|
|
||||||
{ List, ...others }: ViewsComponents = {},
|
|
||||||
{ isUploadEnabled, gridView }: Options
|
|
||||||
): ViewsComponents => ({
|
|
||||||
...others,
|
|
||||||
List: isUploadEnabled ? DefaultList(gridView) : List,
|
|
||||||
});
|
|
|
@ -167,8 +167,6 @@ export type PayloadImage = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const payload = {
|
export const payload = {
|
||||||
getSlugsWeapons: async (): Promise<string[]> =>
|
|
||||||
await (await request(payloadApiUrl(Collections.Weapons, "slugs"))).json(),
|
|
||||||
getWeapon: async (slug: string): Promise<EndpointWeapon> =>
|
getWeapon: async (slug: string): Promise<EndpointWeapon> =>
|
||||||
await (await request(payloadApiUrl(Collections.Weapons, `slug/${slug}`))).json(),
|
await (await request(payloadApiUrl(Collections.Weapons, `slug/${slug}`))).json(),
|
||||||
getEras: async (): Promise<EndpointEra[]> =>
|
getEras: async (): Promise<EndpointEra[]> =>
|
||||||
|
|
|
@ -4,8 +4,6 @@ import { readFileSync } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import payload from "payload";
|
import payload from "payload";
|
||||||
import { Collections, RecordersRoles } from "./constants";
|
import { Collections, RecordersRoles } from "./constants";
|
||||||
import { Recorder } from "./types/collections";
|
|
||||||
import { PayloadCreateData } from "./types/payload";
|
|
||||||
import { isDefined, isUndefined } from "./utils/asserts";
|
import { isDefined, isUndefined } from "./utils/asserts";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
@ -28,7 +26,6 @@ const start = async () => {
|
||||||
|
|
||||||
await payload.init({
|
await payload.init({
|
||||||
secret: process.env.PAYLOAD_SECRET,
|
secret: process.env.PAYLOAD_SECRET,
|
||||||
mongoURL: process.env.MONGODB_URI,
|
|
||||||
express: app,
|
express: app,
|
||||||
onInit: async () => {
|
onInit: async () => {
|
||||||
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
|
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
|
||||||
|
@ -43,16 +40,15 @@ const start = async () => {
|
||||||
if (recorders.docs.length === 0) {
|
if (recorders.docs.length === 0) {
|
||||||
payload.logger.info("Seeding some initial data");
|
payload.logger.info("Seeding some initial data");
|
||||||
|
|
||||||
const recorder: PayloadCreateData<Recorder> = {
|
|
||||||
email: process.env.SEEDING_ADMIN_EMAIL,
|
|
||||||
password: process.env.SEEDING_ADMIN_PASSWORD,
|
|
||||||
username: process.env.SEEDING_ADMIN_USERNAME,
|
|
||||||
role: [RecordersRoles.Admin, RecordersRoles.Api],
|
|
||||||
anonymize: false,
|
|
||||||
};
|
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: Collections.Recorders,
|
collection: Collections.Recorders,
|
||||||
data: recorder,
|
data: {
|
||||||
|
email: process.env.SEEDING_ADMIN_EMAIL,
|
||||||
|
password: process.env.SEEDING_ADMIN_PASSWORD,
|
||||||
|
username: process.env.SEEDING_ADMIN_USERNAME,
|
||||||
|
role: [RecordersRoles.Admin, RecordersRoles.Api],
|
||||||
|
anonymize: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,16 @@ html[data-theme="light"] {
|
||||||
--color-base-1000: #000000;
|
--color-base-1000: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-type.row {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-type.radio-group {
|
||||||
|
> ul {
|
||||||
|
padding: 0.75rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.field-type.array-field.group-array {
|
.field-type.array-field.group-array {
|
||||||
> .array-field__header {
|
> .array-field__header {
|
||||||
.array-field__header-actions {
|
.array-field__header-actions {
|
||||||
|
|
|
@ -25,34 +25,36 @@ export type ContentFoldersTranslation = {
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
collections: {
|
collections: {
|
||||||
"library-items": LibraryItem;
|
'library-items': LibraryItem;
|
||||||
contents: Content;
|
contents: Content;
|
||||||
"contents-folders": ContentsFolder;
|
'contents-folders': ContentsFolder;
|
||||||
posts: Post;
|
posts: Post;
|
||||||
"chronology-items": ChronologyItem;
|
'chronology-items': ChronologyItem;
|
||||||
"chronology-eras": ChronologyEra;
|
'chronology-eras': ChronologyEra;
|
||||||
weapons: Weapon;
|
weapons: Weapon;
|
||||||
"weapons-groups": WeaponsGroup;
|
'weapons-groups': WeaponsGroup;
|
||||||
"weapons-thumbnails": WeaponsThumbnail;
|
'weapons-thumbnails': WeaponsThumbnail;
|
||||||
"contents-thumbnails": ContentsThumbnail;
|
'contents-thumbnails': ContentsThumbnail;
|
||||||
"library-items-thumbnails": LibraryItemThumbnail;
|
'library-items-thumbnails': LibraryItemThumbnail;
|
||||||
"library-items-scans": LibraryItemScans;
|
'library-items-scans': LibraryItemScans;
|
||||||
"library-items-gallery": LibraryItemGallery;
|
'library-items-gallery': LibraryItemGallery;
|
||||||
"recorders-thumbnails": RecordersThumbnail;
|
'recorders-thumbnails': RecordersThumbnail;
|
||||||
"posts-thumbnails": PostThumbnail;
|
'posts-thumbnails': PostThumbnail;
|
||||||
files: File;
|
files: File;
|
||||||
videos: Video;
|
videos: Video;
|
||||||
"videos-channels": VideosChannel;
|
'videos-channels': VideosChannel;
|
||||||
languages: Language;
|
languages: Language;
|
||||||
currencies: Currency;
|
currencies: Currency;
|
||||||
recorders: Recorder;
|
recorders: Recorder;
|
||||||
keys: Key;
|
keys: Key;
|
||||||
|
'payload-preferences': PayloadPreference;
|
||||||
|
'payload-migrations': PayloadMigration;
|
||||||
};
|
};
|
||||||
globals: {};
|
globals: {};
|
||||||
}
|
}
|
||||||
export interface LibraryItem {
|
export interface LibraryItem {
|
||||||
id: string;
|
id: string;
|
||||||
itemType?: "Textual" | "Audio" | "Video" | "Game" | "Other";
|
itemType?: 'Textual' | 'Audio' | 'Video' | 'Game' | 'Other';
|
||||||
slug: string;
|
slug: string;
|
||||||
thumbnail?: string | LibraryItemThumbnail;
|
thumbnail?: string | LibraryItemThumbnail;
|
||||||
pretitle?: string;
|
pretitle?: string;
|
||||||
|
@ -115,8 +117,8 @@ export interface LibraryItem {
|
||||||
subtype?: string[] | Key[];
|
subtype?: string[] | Key[];
|
||||||
languages?: string[] | Language[];
|
languages?: string[] | Language[];
|
||||||
pageCount?: number;
|
pageCount?: number;
|
||||||
bindingType?: "Paperback" | "Hardcover";
|
bindingType?: 'Paperback' | 'Hardcover';
|
||||||
pageOrder?: "LeftToRight" | "RightToLeft";
|
pageOrder?: 'LeftToRight' | 'RightToLeft';
|
||||||
};
|
};
|
||||||
audio?: {
|
audio?: {
|
||||||
audioSubtype?: string[] | Key[];
|
audioSubtype?: string[] | Key[];
|
||||||
|
@ -160,7 +162,7 @@ export interface LibraryItem {
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
_status?: "draft" | "published";
|
_status?: 'draft' | 'published';
|
||||||
}
|
}
|
||||||
export interface LibraryItemThumbnail {
|
export interface LibraryItemThumbnail {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -278,16 +280,16 @@ export interface Key {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type:
|
type:
|
||||||
| "Contents"
|
| 'Contents'
|
||||||
| "LibraryAudio"
|
| 'LibraryAudio'
|
||||||
| "LibraryVideo"
|
| 'LibraryVideo'
|
||||||
| "LibraryTextual"
|
| 'LibraryTextual'
|
||||||
| "LibraryGroup"
|
| 'LibraryGroup'
|
||||||
| "Library"
|
| 'Library'
|
||||||
| "Weapons"
|
| 'Weapons'
|
||||||
| "GamePlatforms"
|
| 'GamePlatforms'
|
||||||
| "Categories"
|
| 'Categories'
|
||||||
| "Wordings";
|
| 'Wordings';
|
||||||
translations?: CategoryTranslations;
|
translations?: CategoryTranslations;
|
||||||
}
|
}
|
||||||
export interface Language {
|
export interface Language {
|
||||||
|
@ -297,7 +299,7 @@ export interface Language {
|
||||||
export interface File {
|
export interface File {
|
||||||
id: string;
|
id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
type: "LibraryScans" | "LibrarySoundtracks" | "ContentVideo" | "ContentAudio";
|
type: 'LibraryScans' | 'LibrarySoundtracks' | 'ContentVideo' | 'ContentAudio';
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
@ -317,10 +319,12 @@ export interface Content {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
|
textContent?: {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
textTranscribers?: string[] | Recorder[];
|
textTranscribers?: string[] | Recorder[];
|
||||||
textTranslators?: string[] | Recorder[];
|
textTranslators?: string[] | Recorder[];
|
||||||
textProofreaders?: string[] | Recorder[];
|
textProofreaders?: string[] | Recorder[];
|
||||||
textContent?: (TextBlock | Section | Tabs | TranscriptBlock | QuoteBlock)[];
|
|
||||||
textNotes?: string;
|
textNotes?: string;
|
||||||
video?: string | File;
|
video?: string | File;
|
||||||
videoNotes?: string;
|
videoNotes?: string;
|
||||||
|
@ -330,7 +334,7 @@ export interface Content {
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
_status?: "draft" | "published";
|
_status?: 'draft' | 'published';
|
||||||
}
|
}
|
||||||
export interface ContentsThumbnail {
|
export interface ContentsThumbnail {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -376,7 +380,7 @@ export interface Recorder {
|
||||||
avatar?: string | RecordersThumbnail;
|
avatar?: string | RecordersThumbnail;
|
||||||
languages?: string[] | Language[];
|
languages?: string[] | Language[];
|
||||||
biographies?: RecorderBiographies;
|
biographies?: RecorderBiographies;
|
||||||
role?: ("Admin" | "Recorder" | "Api")[];
|
role?: ('Admin' | 'Recorder' | 'Api')[];
|
||||||
anonymize: boolean;
|
anonymize: boolean;
|
||||||
email: string;
|
email: string;
|
||||||
resetPasswordToken?: string;
|
resetPasswordToken?: string;
|
||||||
|
@ -417,193 +421,6 @@ export interface RecordersThumbnail {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export interface TextBlock {
|
|
||||||
content: {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "textBlock";
|
|
||||||
}
|
|
||||||
export interface Section {
|
|
||||||
content?: (Section_Section | Section_Tabs | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section {
|
|
||||||
content?: (
|
|
||||||
| Section_Section_Section
|
|
||||||
| Section_Section_Tabs
|
|
||||||
| TranscriptBlock
|
|
||||||
| QuoteBlock
|
|
||||||
| TextBlock
|
|
||||||
)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section {
|
|
||||||
content?: (
|
|
||||||
| Section_Section_Section_Section
|
|
||||||
| Section_Section_Section_Tabs
|
|
||||||
| TranscriptBlock
|
|
||||||
| QuoteBlock
|
|
||||||
| TextBlock
|
|
||||||
)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section_Section {
|
|
||||||
content?: (Section_Section_Section_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section_Section_Section {
|
|
||||||
content?: (TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface TranscriptBlock {
|
|
||||||
lines: (LineBlock | CueBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "transcriptBlock";
|
|
||||||
}
|
|
||||||
export interface LineBlock {
|
|
||||||
content: {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "lineBlock";
|
|
||||||
}
|
|
||||||
export interface CueBlock {
|
|
||||||
content: string;
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "cueBlock";
|
|
||||||
}
|
|
||||||
export interface QuoteBlock {
|
|
||||||
from: string;
|
|
||||||
content: {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "quoteBlock";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section_Tabs {
|
|
||||||
tabs?: Section_Section_Section_Tabs_Tab[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tabs";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section_Tabs_Tab {
|
|
||||||
content?: (Section_Section_Section_Tabs_Tab_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tab";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Section_Tabs_Tab_Section {
|
|
||||||
content?: (TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Tabs {
|
|
||||||
tabs?: Section_Section_Tabs_Tab[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tabs";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Tabs_Tab {
|
|
||||||
content?: (Section_Section_Tabs_Tab_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tab";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Tabs_Tab_Section {
|
|
||||||
content?: (Section_Section_Tabs_Tab_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Section_Tabs_Tab_Section_Section {
|
|
||||||
content?: (TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Tabs {
|
|
||||||
tabs?: Section_Tabs_Tab[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tabs";
|
|
||||||
}
|
|
||||||
export interface Section_Tabs_Tab {
|
|
||||||
content?: (Section_Tabs_Tab_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tab";
|
|
||||||
}
|
|
||||||
export interface Section_Tabs_Tab_Section {
|
|
||||||
content?: (Section_Tabs_Tab_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Tabs_Tab_Section_Section {
|
|
||||||
content?: (Section_Tabs_Tab_Section_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Section_Tabs_Tab_Section_Section_Section {
|
|
||||||
content?: (TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Tabs {
|
|
||||||
tabs?: Tabs_Tab[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tabs";
|
|
||||||
}
|
|
||||||
export interface Tabs_Tab {
|
|
||||||
content?: (Tabs_Tab_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "tab";
|
|
||||||
}
|
|
||||||
export interface Tabs_Tab_Section {
|
|
||||||
content?: (Tabs_Tab_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Tabs_Tab_Section_Section {
|
|
||||||
content?: (Tabs_Tab_Section_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Tabs_Tab_Section_Section_Section {
|
|
||||||
content?: (Tabs_Tab_Section_Section_Section_Section | TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface Tabs_Tab_Section_Section_Section_Section {
|
|
||||||
content?: (TranscriptBlock | QuoteBlock | TextBlock)[];
|
|
||||||
id?: string;
|
|
||||||
blockName?: string;
|
|
||||||
blockType: "section";
|
|
||||||
}
|
|
||||||
export interface ContentsFolder {
|
export interface ContentsFolder {
|
||||||
id: string;
|
id: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
@ -617,21 +434,21 @@ export interface Post {
|
||||||
thumbnail?: string | PostThumbnail;
|
thumbnail?: string | PostThumbnail;
|
||||||
authors:
|
authors:
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'recorders';
|
||||||
value: string;
|
value: string;
|
||||||
relationTo: "recorders";
|
|
||||||
}[]
|
}[]
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'recorders';
|
||||||
value: Recorder;
|
value: Recorder;
|
||||||
relationTo: "recorders";
|
|
||||||
}[];
|
}[];
|
||||||
categories?:
|
categories?:
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'keys';
|
||||||
value: string;
|
value: string;
|
||||||
relationTo: "keys";
|
|
||||||
}[]
|
}[]
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'keys';
|
||||||
value: Key;
|
value: Key;
|
||||||
relationTo: "keys";
|
|
||||||
}[];
|
}[];
|
||||||
translations: {
|
translations: {
|
||||||
language: string | Language;
|
language: string | Language;
|
||||||
|
@ -650,7 +467,7 @@ export interface Post {
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
_status?: "draft" | "published";
|
_status?: 'draft' | 'published';
|
||||||
}
|
}
|
||||||
export interface PostThumbnail {
|
export interface PostThumbnail {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -701,12 +518,12 @@ export interface ChronologyItem {
|
||||||
events: {
|
events: {
|
||||||
source?:
|
source?:
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'contents';
|
||||||
value: string | Content;
|
value: string | Content;
|
||||||
relationTo: "contents";
|
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
relationTo: 'library-items';
|
||||||
value: string | LibraryItem;
|
value: string | LibraryItem;
|
||||||
relationTo: "library-items";
|
|
||||||
};
|
};
|
||||||
translations: {
|
translations: {
|
||||||
language: string | Language;
|
language: string | Language;
|
||||||
|
@ -724,7 +541,7 @@ export interface ChronologyItem {
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
_status?: "draft" | "published";
|
_status?: 'draft' | 'published';
|
||||||
}
|
}
|
||||||
export interface ChronologyEra {
|
export interface ChronologyEra {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -768,7 +585,7 @@ export interface Weapon {
|
||||||
updatedBy: string | Recorder;
|
updatedBy: string | Recorder;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
_status?: "draft" | "published";
|
_status?: 'draft' | 'published';
|
||||||
}
|
}
|
||||||
export interface WeaponsThumbnail {
|
export interface WeaponsThumbnail {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -830,7 +647,7 @@ export interface Video {
|
||||||
id: string;
|
id: string;
|
||||||
uid: string;
|
uid: string;
|
||||||
gone: boolean;
|
gone: boolean;
|
||||||
source: "YouTube" | "NicoNico" | "Tumblr";
|
source: 'YouTube' | 'NicoNico' | 'Tumblr';
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
likes?: number;
|
likes?: number;
|
||||||
|
@ -844,3 +661,62 @@ export interface VideosChannel {
|
||||||
title: string;
|
title: string;
|
||||||
subscribers?: number;
|
subscribers?: number;
|
||||||
}
|
}
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: string;
|
||||||
|
user: {
|
||||||
|
relationTo: 'recorders';
|
||||||
|
value: string | Recorder;
|
||||||
|
};
|
||||||
|
key?: string;
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
batch?: number;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes {
|
||||||
|
collections: {
|
||||||
|
'library-items': LibraryItem
|
||||||
|
'contents': Content
|
||||||
|
'contents-folders': Contents Folder
|
||||||
|
'posts': Post
|
||||||
|
'chronology-items': ChronologyItem
|
||||||
|
'chronology-eras': Chronology Era
|
||||||
|
'weapons': Weapon
|
||||||
|
'weapons-groups': Weapons Group
|
||||||
|
'weapons-thumbnails': Weapons Thumbnail
|
||||||
|
'contents-thumbnails': Contents Thumbnail
|
||||||
|
'library-items-thumbnails': Library Item Thumbnail
|
||||||
|
'library-items-scans': Library Item Scans
|
||||||
|
'library-items-gallery': Library Item Gallery
|
||||||
|
'recorders-thumbnails': Recorders Thumbnail
|
||||||
|
'posts-thumbnails': Post Thumbnail
|
||||||
|
'files': File
|
||||||
|
'videos': Video
|
||||||
|
'videos-channels': Videos Channel
|
||||||
|
'languages': Language
|
||||||
|
'currencies': Currency
|
||||||
|
'recorders': Recorder
|
||||||
|
'keys': Key
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,6 @@
|
||||||
import { CollectionConfig, PayloadRequest } from "payload/types";
|
import { Endpoint } from "payload/config";
|
||||||
|
import { PayloadRequest } from "payload/types";
|
||||||
|
|
||||||
export type PayloadCreateData<T> = Omit<
|
export type CollectionEndpoint = Omit<Endpoint, "root">;
|
||||||
T,
|
|
||||||
"id" | "updatedAt" | "createdAt" | "sizes" | "updatedBy"
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type CollectionEndpoint = NonNullable<CollectionConfig["endpoints"]>[number];
|
|
||||||
|
|
||||||
export type EndpointAccess<U> = (req: PayloadRequest<U>) => boolean;
|
export type EndpointAccess<U> = (req: PayloadRequest<U>) => boolean;
|
||||||
|
|
|
@ -6,10 +6,6 @@ export const isDefined = <T>(value: T | null | undefined): value is T =>
|
||||||
export const isUndefined = <T>(value: T | null | undefined): value is null | undefined =>
|
export const isUndefined = <T>(value: T | null | undefined): value is null | undefined =>
|
||||||
!isDefined(value);
|
!isDefined(value);
|
||||||
|
|
||||||
export const filterDefined = <T>(array: (T | null | undefined)[]): T[] => array.filter(isDefined);
|
|
||||||
|
|
||||||
export const isValidDate = (date: Date): boolean => date instanceof Date && !isNaN(date.getDate());
|
|
||||||
|
|
||||||
export const isNotEmpty = (value: string | null | undefined): value is string =>
|
export const isNotEmpty = (value: string | null | undefined): value is string =>
|
||||||
isDefined(value) && value.trim().length > 0;
|
isDefined(value) && value.trim().length > 0;
|
||||||
|
|
||||||
|
@ -17,7 +13,7 @@ export const isEmpty = (value: string | null | undefined): value is string =>
|
||||||
isUndefined(value) || value.trim().length === 0;
|
isUndefined(value) || value.trim().length === 0;
|
||||||
|
|
||||||
type Span = [number, number];
|
type Span = [number, number];
|
||||||
export const hasNoIntersection = (a: Span, b: Span): boolean => {
|
const hasNoIntersection = (a: Span, b: Span): boolean => {
|
||||||
const [aStart, aEnd] = a;
|
const [aStart, aEnd] = a;
|
||||||
const [bStart, bEnd] = b;
|
const [bStart, bEnd] = b;
|
||||||
return aEnd < bStart || aStart > bEnd;
|
return aEnd < bStart || aStart > bEnd;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { CollectionConfig } from "payload/types";
|
import { CollectionConfig } from "payload/types";
|
||||||
import { Collections } from "../constants";
|
import { Collections } from "../constants";
|
||||||
import { CollectionConfigWithGridView } from "../plugins/payload-grid-view";
|
|
||||||
|
|
||||||
type CollectionConfigWithPlugins = CollectionConfig & CollectionConfigWithGridView;
|
type CollectionConfigWithPlugins = CollectionConfig;
|
||||||
|
|
||||||
export type BuildCollectionConfig = Omit<
|
export type BuildCollectionConfig = Omit<
|
||||||
CollectionConfigWithPlugins,
|
CollectionConfigWithPlugins,
|
||||||
|
|
|
@ -8,6 +8,7 @@ export const findWeaponType = async (name: string): Promise<string> => {
|
||||||
collection: Collections.Keys,
|
collection: Collections.Keys,
|
||||||
where: { name: { equals: name }, type: { equals: KeysTypes.Weapons } },
|
where: { name: { equals: name }, type: { equals: KeysTypes.Weapons } },
|
||||||
});
|
});
|
||||||
|
if (!key.docs[0]) throw new Error(`Weapon type ${name} wasn't found`);
|
||||||
return key.docs[0].id;
|
return key.docs[0].id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +17,8 @@ export const findCategory = async (name: string): Promise<string> => {
|
||||||
collection: Collections.Keys,
|
collection: Collections.Keys,
|
||||||
where: { name: { equals: name }, type: { equals: KeysTypes.Categories } },
|
where: { name: { equals: name }, type: { equals: KeysTypes.Categories } },
|
||||||
});
|
});
|
||||||
return key.docs[0].id;
|
if (!key.docs[0]) throw new Error(`Category ${name} wasn't found`);
|
||||||
|
return key.docs[0]?.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UploadStrapiImage = {
|
type UploadStrapiImage = {
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
import { Block, BlockField } from "payload/types";
|
|
||||||
import { capitalize } from "./string";
|
|
||||||
|
|
||||||
const isDefined = <T>(value: T | null | undefined): value is T =>
|
|
||||||
value !== null && value !== undefined;
|
|
||||||
|
|
||||||
const recursionFieldName = "recursion" as const;
|
|
||||||
|
|
||||||
type BlockConfig<T extends string> = {
|
|
||||||
root: boolean;
|
|
||||||
block: RecursiveBlock<T> | Block;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RecursiveBlock<T extends string> = Omit<Block, "fields" | "interfaceName"> & {
|
|
||||||
[recursionFieldName]: Omit<BlockField, "blocks" | "type"> & {
|
|
||||||
newDepth: (currentDepth: number) => number;
|
|
||||||
condition: (currentDepth: number, parents: T[]) => boolean;
|
|
||||||
blocks: T[];
|
|
||||||
};
|
|
||||||
fields?: Block["fields"];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BlocksConfig<T extends string> = Record<T, BlockConfig<T>>;
|
|
||||||
|
|
||||||
export const generateBlocks = <T extends string>(blocksConfig: BlocksConfig<T>): Block[] => {
|
|
||||||
const isRecursiveBlock = (block: RecursiveBlock<T> | Block): block is RecursiveBlock<T> =>
|
|
||||||
recursionFieldName in block;
|
|
||||||
|
|
||||||
const getInterfaceName = (parents: T[], currentBlockName: T): string => {
|
|
||||||
return [...parents, currentBlockName]
|
|
||||||
.map((blockName) => blocksConfig[blockName].block.slug)
|
|
||||||
.map(capitalize)
|
|
||||||
.join("_");
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCurrentDepth = (parents: T[]): number =>
|
|
||||||
parents.reduce((acc, blockName) => {
|
|
||||||
const block = blocksConfig[blockName].block;
|
|
||||||
if (!isRecursiveBlock(block)) return acc;
|
|
||||||
return block[recursionFieldName].newDepth(acc);
|
|
||||||
}, 1);
|
|
||||||
|
|
||||||
const generateRecursiveBlocks = (parents: T[], blockName: T): Block | undefined => {
|
|
||||||
const currentDepth = getCurrentDepth(parents);
|
|
||||||
const block = blocksConfig[blockName].block;
|
|
||||||
if (!isRecursiveBlock(block)) return block;
|
|
||||||
|
|
||||||
const {
|
|
||||||
slug,
|
|
||||||
labels,
|
|
||||||
fields = [],
|
|
||||||
recursion: { newDepth, blocks, condition, ...fieldsProps },
|
|
||||||
} = block;
|
|
||||||
|
|
||||||
const generatedBlocks = blocks
|
|
||||||
.filter((blockName) => {
|
|
||||||
const block = blocksConfig[blockName].block;
|
|
||||||
if (!isRecursiveBlock(block)) return true;
|
|
||||||
return block[recursionFieldName].condition(currentDepth, parents);
|
|
||||||
})
|
|
||||||
.map((nextBlockName) => generateRecursiveBlocks([...parents, blockName], nextBlockName))
|
|
||||||
.filter(isDefined);
|
|
||||||
|
|
||||||
// Cut dead branches (branches without leafs)
|
|
||||||
if (generatedBlocks.length === 0) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
slug,
|
|
||||||
interfaceName: getInterfaceName(parents, blockName),
|
|
||||||
labels,
|
|
||||||
fields: [
|
|
||||||
...fields,
|
|
||||||
{
|
|
||||||
...fieldsProps,
|
|
||||||
type: "blocks",
|
|
||||||
blocks: generatedBlocks,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const rootBlockNames = Object.entries<BlockConfig<T>>(blocksConfig)
|
|
||||||
.filter(([_, blockConfig]) => blockConfig.root)
|
|
||||||
.map(([blockName]) => blockName as T);
|
|
||||||
|
|
||||||
return rootBlockNames
|
|
||||||
.map((blockName) => generateRecursiveBlocks([], blockName))
|
|
||||||
.filter(isDefined);
|
|
||||||
};
|
|
|
@ -7,7 +7,7 @@ export const shortenEllipsis = (text: string, length: number): string =>
|
||||||
export const formatLanguageCode = (code: string): string =>
|
export const formatLanguageCode = (code: string): string =>
|
||||||
tags(code).valid() ? tags(code).language()?.descriptions()[0] ?? code : code;
|
tags(code).valid() ? tags(code).language()?.descriptions()[0] ?? code : code;
|
||||||
|
|
||||||
export const capitalize = (string: string): string => {
|
const capitalize = (string: string): string => {
|
||||||
const [firstLetter, ...otherLetters] = string;
|
const [firstLetter, ...otherLetters] = string;
|
||||||
if (isUndefined(firstLetter)) return "";
|
if (isUndefined(firstLetter)) return "";
|
||||||
return [firstLetter.toUpperCase(), ...otherLetters].join("");
|
return [firstLetter.toUpperCase(), ...otherLetters].join("");
|
||||||
|
@ -19,6 +19,3 @@ export const formatToCamelCase = (name: string): string =>
|
||||||
.split(/[ \_-]/g)
|
.split(/[ \_-]/g)
|
||||||
.map((part, index) => (index > 0 ? capitalize(part) : part))
|
.map((part, index) => (index > 0 ? capitalize(part) : part))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
export const formatToKebabCase = (name: string): string =>
|
|
||||||
name.toLowerCase().replaceAll(/[ \_]/g, "-");
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ const updatedByField = (): RelationshipField => ({
|
||||||
type: "relationship",
|
type: "relationship",
|
||||||
required: true,
|
required: true,
|
||||||
relationTo: Collections.Recorders,
|
relationTo: Collections.Recorders,
|
||||||
admin: { readOnly: true, position: "sidebar" },
|
admin: { readOnly: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
type BuildVersionedCollectionConfig = Omit<BuildCollectionConfig, "timestamps" | "versions">;
|
type BuildVersionedCollectionConfig = Omit<BuildCollectionConfig, "timestamps" | "versions">;
|
||||||
|
|
Loading…
Reference in New Issue