From f31aa570d1659fb449d7afaa0f685228d5c60c7f Mon Sep 17 00:00:00 2001 From: Ben Merckx Date: Wed, 23 Oct 2024 12:14:39 +0530 Subject: [PATCH] Update page api, update init command --- src/backend/Database.ts | 24 +++++++------- src/backend/test/Example.ts | 62 +++++++++++++++++++++---------------- src/cli/Init.ts | 12 +++---- src/cli/static/init/cms.js | 9 +++--- src/core/Document.ts | 2 +- src/core/Graph.ts | 4 +-- src/core/Page.ts | 49 ++++++++++++++--------------- src/core/Root.ts | 4 +-- src/core/Scope.ts | 4 +-- src/core/media/MediaRoot.ts | 7 ++--- 10 files changed, 90 insertions(+), 87 deletions(-) diff --git a/src/backend/Database.ts b/src/backend/Database.ts index 4199b7bdf..c6d00b799 100644 --- a/src/backend/Database.ts +++ b/src/backend/Database.ts @@ -1,9 +1,10 @@ +import {reportHalt} from 'alinea/cli/util/Report' import {Config} from 'alinea/core/Config' import {SyncResponse, Syncable} from 'alinea/core/Connection' import {EntryRecord, createRecord, parseRecord} from 'alinea/core/EntryRecord' import {createId} from 'alinea/core/Id' import {Mutation, MutationType} from 'alinea/core/Mutation' -import {PageSeed} from 'alinea/core/Page' +import {Page} from 'alinea/core/Page' import {Resolver} from 'alinea/core/Resolver' import {Root} from 'alinea/core/Root' import {Schema} from 'alinea/core/Schema' @@ -47,7 +48,7 @@ interface Seed { workspace: string root: string filePath: string - page: PageSeed + page: Page } function seedKey(workspace: string, root: string, filePath: string) { @@ -522,7 +523,7 @@ export class Database implements Syncable { } const pathData = entryPath === 'index' ? '' : entryPath - const seedData = seed ? PageSeed.data(seed.page).partial : {} + const seedData = seed ? Page.data(seed.page).fields : {} const title = record.title ?? seedData?.title ?? '' const entryData = { ...seedData, @@ -569,13 +570,13 @@ export class Database implements Syncable { const {i18n} = Root.data(root) const locales = i18n?.locales ?? [undefined] for (const locale of locales) { - const pages: Array = entries(root) + const pages: Array = entries(root) const target = locale ? `/${locale}` : '/' while (pages.length > 0) { const [pagePath, page] = pages.shift()! const path = pagePath.split('/').map(slugify).join('/') - if (!PageSeed.isPageSeed(page)) continue - const {type} = PageSeed.data(page) + if (!Page.isPage(page)) continue + const {type} = Page.data(page) const filePath = paths.join(target, path) + '.json' const typeName = typeNames.get(type) if (!typeName) continue @@ -589,7 +590,7 @@ export class Database implements Syncable { }) const children = entries(page).map( ([childPath, child]) => - [paths.join(path, childPath), child as PageSeed] as const + [paths.join(path, childPath), child as Page] as const ) pages.push(...children) } @@ -691,8 +692,7 @@ export class Database implements Syncable { seenVersions.push(`${entry.id}.${entry.phase}`) inserted.push(`${entry.id}.${entry.phase}`) } catch (e: any) { - console.info(`> skipped ${file.filePath} — ${e.message}`) - console.error(e) + reportHalt(`${e.message} @ ${file.filePath}`) process.exit(1) } } @@ -705,7 +705,7 @@ export class Database implements Syncable { for (const seed of this.seed.values()) { const key = seedKey(seed.workspace, seed.root, seed.filePath) if (seenSeeds.has(key)) continue - const {type, partial} = PageSeed.data(seed.page) + const {type, fields} = Page.data(seed.page) const typeName = typeNames.get(type) if (!typeName) continue const root = this.config.workspaces[seed.workspace][seed.root] @@ -724,8 +724,8 @@ export class Database implements Syncable { type: typeName, index: 'a0', seeded: seed.filePath, - title: partial.title ?? '', - data: partial + title: fields.title ?? '', + data: fields }), seed, seed diff --git a/src/backend/test/Example.ts b/src/backend/test/Example.ts index 825ee0095..1050dcb1e 100644 --- a/src/backend/test/Example.ts +++ b/src/backend/test/Example.ts @@ -173,15 +173,15 @@ export function createExample() { pages: root('Pages', { contains: ['Page', 'Container'], entries: { - entry1: page(Page, {title: 'Test title'}), - entry2: page( - Container, - {title: 'Entry 2'}, - { - entry3: page(Page, {title: 'Entry 3'}) + entry1: page({type: Page, fields: {title: 'Test title'}}), + entry2: page({ + type: Container, + fields: {title: 'Entry 2'}, + children: { + entry3: page({type: Page, fields: {title: 'Entry 3'}}) } - ), - container1: page(Container, {title: 'Container 1'}) + }), + container1: page({type: Container, fields: {title: 'Container 1'}}) } }), multiLanguage: root('Multi language', { @@ -190,29 +190,37 @@ export function createExample() { locales: ['en', 'fr'] }, entries: { - localised1: page(Page, {title: 'Test title'}), - localised2: page( - Container, - {title: 'Entry 2'}, - { - localised3: page(Page, {title: 'Entry 3'}) + localised1: page({type: Page, fields: {title: 'Test title'}}), + localised2: page({ + type: Container, + fields: {title: 'Entry 2'}, + children: { + localised3: page({type: Page, fields: {title: 'Entry 3'}}) } - ) + }) } }), media: createMediaRoot({ - dir: page(MediaLibrary, {title: 'Media folder'}), - 'file1.png': page(MediaFile, { - title: 'File 1', - path: 'file1.png', - extension: '.png', - size: 1000, - width: 120, - height: 120, - hash: 'hash1', - preview: `data:image/png;base64,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`, - averageColor: '#ffffff', - focus: {x: 0.5, y: 0.5} + dir: page({ + type: MediaLibrary, + fields: {title: 'Media folder'}, + children: { + 'file1.png': page({ + type: MediaFile, + fields: { + title: 'File 1', + path: 'file1.png', + extension: '.png', + size: 1000, + width: 120, + height: 120, + hash: 'hash1', + preview: `data:image/png;base64,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`, + averageColor: '#ffffff', + focus: {x: 0.5, y: 0.5} + } + }) + } }) }) } diff --git a/src/cli/Init.ts b/src/cli/Init.ts index a898c967d..540123953 100644 --- a/src/cli/Init.ts +++ b/src/cli/Init.ts @@ -49,13 +49,11 @@ export async function init(options: InitOptions) { path.join(cwd, 'content/pages/welcome.json'), JSON.stringify( { - id: createId(), - type: 'Page', - title: 'Welcome', - alinea: { - index: 'a0', - seeded: 'welcome.json' - } + _id: createId(), + _type: 'Page', + _index: 'a0', + _seeded: 'welcome.json', + title: 'Welcome' }, null, 2 diff --git a/src/cli/static/init/cms.js b/src/cli/static/init/cms.js index 85abb6512..45b8103b1 100644 --- a/src/cli/static/init/cms.js +++ b/src/cli/static/init/cms.js @@ -20,11 +20,12 @@ export const cms = createCMS({ pages: Config.root('Example project', { contains: ['Page'], entries: { - welcome: Config.page( - Page({ + welcome: Config.page({ + type: Page, + fields: { title: 'Welcome' - }) - ) + } + }) } }), media: Config.media() diff --git a/src/core/Document.ts b/src/core/Document.ts index 53c73b4e2..cafa34436 100644 --- a/src/core/Document.ts +++ b/src/core/Document.ts @@ -6,7 +6,7 @@ import {IcRoundDescription} from 'alinea/ui/icons/IcRoundDescription' import {IcRoundShare} from 'alinea/ui/icons/IcRoundShare' import {FieldsDefinition, Type, TypeConfig, type} from './Type.js' -export interface Document { +export type Document = { title: TextField path: PathField metadata: MetadataField diff --git a/src/core/Graph.ts b/src/core/Graph.ts index 7e3074f89..621615df7 100644 --- a/src/core/Graph.ts +++ b/src/core/Graph.ts @@ -4,14 +4,14 @@ import {Config} from './Config.js' import {EntryFields} from './EntryFields.js' import {Expr} from './Expr.js' import {Filter} from './Filter.js' -import {PageSeed} from './Page.js' +import {Page} from './Page.js' import {PreviewRequest} from './Preview.js' import {Resolver} from './Resolver.js' import {Type} from './Type.js' import {hasExact} from './util/Checks.js' import {Expand} from './util/Types.js' -export type Location = Root | Workspace | PageSeed | Array +export type Location = Root | Workspace | Page | Array type EmptyObject = Record type FieldsOf = Types extends Type diff --git a/src/core/Page.ts b/src/core/Page.ts index dde6d6797..090adb8d0 100644 --- a/src/core/Page.ts +++ b/src/core/Page.ts @@ -1,43 +1,40 @@ -import {Type} from './Type.js' +import {FieldsDefinition, Type} from './Type.js' -export interface PageSeedData { +export interface PageData { type: Type - partial: Record + fields: Record } -export type PageSeed< - Definition = object, - Children extends Record = Record> +export type Page< + Children extends Record = Record > = Children & { - [PageSeed.Data]: PageSeedData + [Page.Data]: PageData } -export namespace PageSeed { +export namespace Page { export const Data = Symbol.for('@alinea/Page.Data') - export function data(page: PageSeed): PageSeedData { - return page[PageSeed.Data] + export function data(page: Page): PageData { + return page[Page.Data] } - export function isPageSeed(page: any): page is PageSeed { - return Boolean(page && page[PageSeed.Data]) + export function isPage(page: any): page is Page { + return Boolean(page && page[Page.Data]) } } -export function page< - Definition, - Children extends Record> ->( - type: Type, - partial: Partial> = {}, +export interface PageConfig { + type: Type + fields?: Partial> children?: Children -): PageSeed { - children = children ?? ({} as Children) +} + +export function page< + Fields extends FieldsDefinition, + Children extends Record +>(config: PageConfig): Page { return { - ...children, - [PageSeed.Data]: { - type: type, - partial: partial - } - } + ...config.children, + [Page.Data]: config + } as any } diff --git a/src/core/Root.ts b/src/core/Root.ts index 0c5c44cf2..4842e6c98 100644 --- a/src/core/Root.ts +++ b/src/core/Root.ts @@ -2,7 +2,7 @@ import * as cito from 'cito' import type {ComponentType} from 'react' import {getRoot, hasRoot, HasRoot, internalRoot} from './Internal.js' import {Label} from './Label.js' -import {PageSeed} from './Page.js' +import {Page} from './Page.js' import {Preview} from './Preview.js' import {Schema} from './Schema.js' import {Type} from './Type.js' @@ -23,7 +23,7 @@ export interface RootMeta { } export interface EntriesDefinition { - [key: string]: PageSeed + [key: string]: Page } export interface RootData extends RootMeta { diff --git a/src/core/Scope.ts b/src/core/Scope.ts index 9d1cd5bc5..e0073fa7b 100644 --- a/src/core/Scope.ts +++ b/src/core/Scope.ts @@ -3,13 +3,13 @@ import {Config} from './Config.js' import {Expr} from './Expr.js' import {Field} from './Field.js' import {getExpr, hasExpr} from './Internal.js' -import {PageSeed} from './Page.js' +import {Page} from './Page.js' import {Root} from './Root.js' import {Type} from './Type.js' import {entries} from './util/Objects.js' const scopes = new WeakMap() -type Entity = Workspace | Root | Type | Field | Expr | PageSeed +type Entity = Workspace | Root | Type | Field | Expr | Page const ENTITY_KEY = '@alinea.Entity' const EXPR_KEY = '@alinea.Expr' diff --git a/src/core/media/MediaRoot.ts b/src/core/media/MediaRoot.ts index 6a131347c..0f9ba8ab7 100644 --- a/src/core/media/MediaRoot.ts +++ b/src/core/media/MediaRoot.ts @@ -1,11 +1,10 @@ import {IcRoundPermMedia} from 'alinea/ui/icons/IcRoundPermMedia' -import {PageSeed} from '../Page.js' +import {Page} from '../Page.js' import {Root, root} from '../Root.js' -export type MediaRoot> = - Root +export type MediaRoot> = Root -export function createMediaRoot>( +export function createMediaRoot>( children: Children = {} as Children ) { return root('Media', {