Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SLB-188: Decap integration #117

Merged
merged 20 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
86c39ca
refactor(SLB-188): simplify source typing for easer zod schemas
pmelab Dec 14, 2023
fcd6aad
refactor(SLB-188): simplify test data and structure
pmelab Dec 13, 2023
594602f
feat(SLB-188): generic preview function
pmelab Dec 13, 2023
295e3fb
refactor(SLB-188): clean up page collection code
pmelab Dec 13, 2023
fcf24fe
refactor(SLB-188): fix broken test data
pmelab Dec 13, 2023
3fb4753
feat(SLB-188): expose getPages function
pmelab Dec 13, 2023
8be7624
fix: lock graphql version
pmelab Dec 13, 2023
8c81cac
chore(SLB-188): merge content changes to release
pmelab Dec 14, 2023
623c4ab
feat(SLB-188): separate decap pages from drupal pages
pmelab Dec 14, 2023
5f487cb
feat(SLB-188): source and render decap pages
pmelab Dec 14, 2023
049576a
feat(SLB-188): serve decap ui in /admin subfolder
pmelab Dec 14, 2023
3370e10
ci: clear the drupal cache when schema changes
pmelab Dec 14, 2023
eb7a781
chore(SLB-188): adapt schema test cases to changes
pmelab Dec 14, 2023
05449f3
test(SLB-188): add e2e test case for decap pages
pmelab Dec 14, 2023
a7b9c51
refactor(SLB-188): remove leftover debug log
pmelab Dec 19, 2023
c06a8cf
refactor(SLB-188): fix naming of decap page template
pmelab Dec 19, 2023
18a995f
refactor(SLB-188): separate drupal and decap previews
pmelab Dec 19, 2023
2fcdfa8
fix: upgrade @amazeelabs/gatsby-silverback-cloudinary
pmelab Dec 19, 2023
1a430ae
fix(SLB-188): add missing 'originalSrc' to decap images
pmelab Dec 19, 2023
6f4891b
fix: add missing output declarations for autoloader files
pmelab Dec 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions .gitpod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ tasks:
- name: Codegen
init: gp sync-await setup
command: pnpm --filter @custom/schema run watch
- name: Decap Dev
init: gp sync-await setup
command: pnpm run --filter @custom/decap dev
- name: Decap Proxy
init: gp sync-await setup
command: pnpm run --filter @custom/decap start:proxy
- name: Decap
command: pnpm run --filter @custom/decap start
- name: Decap Dev
init: gp sync-await setup
command: pnpm run --filter @custom/decap start:decap
command: pnpm run --filter @custom/decap dev

image:
file: .gitpod.Dockerfile
Expand Down Expand Up @@ -74,9 +71,6 @@ ports:
- port: 5173
name: Decap Dev
onOpen: notify
- port: 8889
name: Decap
onOpen: notify
- port: 8081
name: Decap Proxy
onOpen: notify
2 changes: 1 addition & 1 deletion apps/cms/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dependsOn": ["prep:database"]
},
"prep:database": {
"dependsOn": ["prep:composer"],
"dependsOn": ["prep:composer", "^prep"],
"inputs": [
"turbo-seed.txt",
"prep-database.sh",
Expand Down
13 changes: 0 additions & 13 deletions apps/decap/data/page/decap-404.yml

This file was deleted.

3 changes: 1 addition & 2 deletions apps/decap/data/page/decap-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ en:
caption: Here is an ***image***, for good measure.
alt: Some architecture.
image: /apps/decap/media/portrait.jpg
de:
id: LFdYu4b6OsjTROxTsYep7
de: {}
12 changes: 0 additions & 12 deletions apps/decap/data/page/decap-home.yml

This file was deleted.

3 changes: 1 addition & 2 deletions apps/decap/data/site.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
homePage: /decap-home
notFoundPage: /decap-404
email: [email protected]
37 changes: 20 additions & 17 deletions apps/decap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,47 @@
"private": true,
"version": "0.0.0",
"main": "build/index.js",
"types": "build/index.d.ts",
"type": "module",
"scripts": {
"dev": "vite --host",
"prep": "pnpm prep:vite",
"prep": "pnpm prep:vite && pnpm prep:scripts",
"prep:vite": "vite build",
"start:proxy": "GIT_REPO_DIRECTORY=../../ pnpm netlify-cms-proxy-server",
"start:decap": "pnpm serve -p 8889",
"prep:scripts": "tsup",
"start": "GIT_REPO_DIRECTORY=../../ pnpm netlify-cms-proxy-server",
"test:static": "tsc --noEmit && eslint \"**/*.{ts,tsx,js,jsx}\" --ignore-path=\"./.eslintignore\"",
"test:unit": "vitest run --passWithNoTests"
},
"dependencies": {
"@amazeelabs/cloudinary-responsive-image": "^1.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@amazeelabs/graphql-directives": "^1.2.2",
"@custom/schema": "workspace:*",
"@custom/ui": "workspace:*",
"netlify-cms-app": "^2.15.72",
"nanoid": "^4.0.2",
"zod": "^3.21.4",
"graphql": "^16.7.1",
"unified": "^10.1.2",
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0",
"nanoid": "^4.0.2",
"netlify-cms-app": "^2.15.72",
"netlify-cms-core": "^2.55.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rehype-sanitize": "^5.0.1",
"rehype-stringify": "^9.0.3",
"yaml": "^2.3.1"
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0",
"unified": "^10.1.2",
"yaml": "^2.3.1",
"zod": "^3.21.4"
},
"devDependencies": {
"tsup": "^7.2.0",
"serve": "^14.2.0",
"netlify-cms-proxy-server": "^1.3.24",
"@amazeelabs/gatsby-source-silverback": "^1.13.2",
"@types/node": "^20.4.9",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"netlify-cms-proxy-server": "^1.3.24",
"tsup": "^7.2.0",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"@types/node": "^20.4.9"
"vite": "^4.4.5"
}
}
12 changes: 12 additions & 0 deletions apps/decap/src/collections/page.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { dirname, resolve } from 'path';
import { expect, test } from 'vitest';

import { getPages } from '..';

test('getPages', () => {
const dir = resolve(
dirname(new URL(import.meta.url).pathname),
'../../data/page',
);
expect(() => getPages(dir)).not.toThrow();
});
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { ImageSource, PreviewPageQuery, Url } from '@custom/schema';
import { SilverbackSource } from '@amazeelabs/gatsby-source-silverback';
import {
BlockMarkupSource,
BlockMediaSource,
DecapPageSource,
LocaleSource,
MediaImageSource,
PageSource,
} from '@custom/schema/source';
import { Page } from '@custom/ui/routes/Page';
import {
CmsCollection,
CmsField,
PreviewTemplateComponentProps,
} from 'netlify-cms-core';
import { z, ZodType, ZodTypeDef } from 'zod';
import fs from 'fs';
import type { CmsCollection, CmsField } from 'netlify-cms-core';
import yaml from 'yaml';
import { z } from 'zod';

import { PreviewFrame } from '../helpers/frame';
import { transformMarkdown } from '../helpers/markdown';
import { useQuery } from '../helpers/query';

// =============================================================================
// Decap CMS collection definition.
Expand Down Expand Up @@ -139,112 +134,87 @@ export const PageCollection: CmsCollection = {
// Transformation schema definitions.
// =============================================================================

const BlockMarkupSchema: ZodType<BlockMarkupSource, ZodTypeDef, unknown> = z
const BlockMarkupSchema = z
.object({
type: z.literal('text'),
text: transformMarkdown,
})
.transform(({ text }) => {
.transform(({ text }): BlockMarkupSource => {
return {
__typename: 'BlockMarkup',
markup: text,
};
});

const BlockMediaImageSchema: ZodType<BlockMediaSource, ZodTypeDef, unknown> = z
const BlockMediaImageSchema = z
.object({
type: z.literal('image'),
alt: z.string(),
image: z.string(),
caption: transformMarkdown,
})
.transform(({ image, alt, caption }) => {
.transform(({ image, alt, caption }): BlockMediaSource => {
return {
__typename: 'BlockMedia',
media: {
__typename: 'MediaImage',
source: image as ImageSource,
source: image,
alt,
},
caption: caption,
};
});

export const pageSchema: ZodType<PageSource, ZodTypeDef, unknown> = z
.object({
__typename: z.literal('Page').optional().default('Page'),
id: z.string(),
title: z.string(),
locale: z.string().transform((l) => l as LocaleSource),
path: z.string().transform((p) => p as Url),
hero: z.object({
__typename: z.literal('Hero').optional().default('Hero'),
headline: z.string(),
lead: z.string().optional(),
image: z
.string()
.optional()
.transform((s) => s as ImageSource)
.transform(
(source) =>
({
export const pageSchema = z.object({
__typename: z.literal('DecapPage').optional().default('DecapPage'),
id: z.string(),
title: z.string(),
locale: z.string().transform((l) => l as LocaleSource),
path: z.string(),
hero: z.object({
__typename: z.literal('Hero').optional().default('Hero'),
headline: z.string(),
lead: z.string().optional(),
image: z
.string()
.optional()
.transform((source): MediaImageSource | undefined =>
source
? {
__typename: 'MediaImage',
source,
alt: '',
} satisfies MediaImageSource),
),
}),
content: z.array(z.union([BlockMarkupSchema, BlockMediaImageSchema])),
})
.transform((page) => ({
...page,
id: `${page.id}:${page.locale}`,
}));

// =============================================================================
// Decap CMS preview component.
// =============================================================================
export function PagePreview({
entry,
getAsset,
}: PreviewTemplateComponentProps) {
// Extract data from Decap input.
const input = entry.toJS().data;

// Parse that input and transform it to a GraphQL Source input.
const parsed = pageSchema.safeParse({ ...input, locale: 'en' });
if (!parsed.success) {
console.error(parsed.error);
}

const previewSourceData = parsed.success
? parsed.data
: ({
__typename: 'Page',
title: '[Missing title]',
path: '/preview' as Url,
locale: 'en',
} satisfies PageSource);

// Execute the "Preview" query on that source input to transform
// data into the exact shape of the query result expected by the
// route.
const data = useQuery(
PreviewPageQuery,
{
previewPage: previewSourceData,
} satisfies PreviewPageQuery,
{
id: '',
rid: '',
locale: '',
},
(src) => getAsset(src).url,
);
}
: undefined,
),
}),
content: z.array(z.union([BlockMarkupSchema, BlockMediaImageSchema])),
});

return (
<PreviewFrame>
{data?.previewPage ? <Page page={data.previewPage} /> : null}
</PreviewFrame>
);
}
export const getPages: (dir: string) => SilverbackSource<DecapPageSource> =
(dir: string) => () => {
const pages: Array<[string, DecapPageSource]> = [];
fs.readdirSync(dir)
.filter((file) => file.endsWith('.yml'))
.forEach((file) => {
const content = yaml.parse(fs.readFileSync(`${dir}/${file}`, 'utf-8'));
Object.keys(content).forEach((lang) => {
if (Object.keys(content[lang]).length < 2) {
return;
}
const input = {
...content[lang],
locale: lang,
};
const page = pageSchema.safeParse(input);
if (page.success) {
pages.push([page.data.id, page.data]);
} else {
console.warn(`Error parsing ${file} (${lang}):`);
console.warn(page.error.message);
console.warn('Input:', content[lang]);
}
});
});
return pages;
};
18 changes: 8 additions & 10 deletions apps/decap/src/helpers/markdown.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Markup } from '@custom/schema';
import rehypeSanitize from 'rehype-sanitize';
import rehypeStringify from 'rehype-stringify';
import remarkParse from 'remark-parse';
Expand All @@ -9,13 +8,12 @@ import { z } from 'zod';
export const transformMarkdown = z
.string()
.optional()
.transform(
(t) =>
unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSanitize)
.use(rehypeStringify)
.processSync(t)
.toString() as Markup,
.transform((t) =>
unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSanitize)
.use(rehypeStringify)
.processSync(t)
.toString(),
);
Loading
Loading