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

fix(filtering, page, next): editing bugs on NextJS #2090

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 31 additions & 15 deletions packages/bodiless-backend/src/page.ts
Expand Up @@ -23,9 +23,17 @@ import Logger from './logger';

const logger = new Logger('BACKEND');

const getDirectories = (dir: string) => fs
.readdirSync(dir)
.filter((file) => fs.statSync(`${dir}/${file}`).isDirectory());
const getDirectories = (dir: string) => {
try {
return fs
.readdirSync(dir)
.filter((file) => fs.statSync(`${dir}/${file}`).isDirectory());
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What error are we ignoring here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we check for subdirs, if there is any error, returns an empty array.

//
}
return [];
};

// @todo: update to fs.mkdir - once we on node > 10.12.0
// we can leverage fs.mkdir since it supports { recursive: true }
function ensureDirectoryExistence(filePath: string): void {
Expand Down Expand Up @@ -397,12 +405,16 @@ class Page {

directoryExists(newDirectory: PathLike) {
const readPromise = new Promise((resolve) => {
fs.access(newDirectory, err => {
if (!err) {
resolve('The page cannot be moved. Directory exists');
}
resolve(this);
});
try {
fs.access(newDirectory, err => {
if (!err) {
resolve('The page cannot be moved. Directory exists');
}
resolve(this);
});
} catch (error) {
resolve('The page cannot be moved.');
}
});
return readPromise;
}
Expand Down Expand Up @@ -434,12 +446,16 @@ class Page {
return;
}

fs.rmdir(this.directory, { recursive: true }, (err) => {
if (err) {
reject(err);
}
resolve(this);
});
try {
fs.rmdir(this.directory, { recursive: true }, (err) => {
if (err) {
reject(err);
}
resolve(this);
});
} catch (error) {
resolve('The page cannot be deleted.');
}
});
return readPromise;
}
Expand Down
15 changes: 9 additions & 6 deletions packages/bodiless-filtering/src/TagButton/TagModel.tsx
Expand Up @@ -14,17 +14,20 @@

import isEmpty from 'lodash/isEmpty';
import { useNode } from '@bodiless/data';
import { TagsNodeType } from './types';
import { TagType } from '@bodiless/core';
import { TagsNodeType, LegacyTagType } from './types';

const legacyDataTransformer = (tag: any) => ({
value: tag.value || tag.id,
label: tag.label || tag.name
});
const legacyDataTransformer = (tag: (LegacyTagType & TagType)) => (
Object.assign(tag, {
value: tag.value || tag.id,
label: tag.label || tag.name
})
);

const useTagsAccessors = () => {
const { node } = useNode<TagsNodeType>();
return {
getTags: () => node.data.tags || [],
getTags: () => (node.data.tags || []).map(legacyDataTransformer),
tag: isEmpty(node.data.tags) ? { value: '', label: '' } : legacyDataTransformer(node.data.tags[0]),
nodeId: node.path[node.path.length - 2] === 'default' ? node.path.toString() : node.path[node.path.length - 2],
};
Expand Down
2 changes: 1 addition & 1 deletion packages/bodiless-filtering/src/TagButton/types.tsx
Expand Up @@ -14,7 +14,7 @@

import { TagType } from '@bodiless/core';

type LegacyTagType = {
export type LegacyTagType = {
id?: string | number | symbol | null,
name?: string
};
Expand Down
Expand Up @@ -59,7 +59,7 @@ export const tagButtonOptions: TagButtonType = {

const suggestions = getSuggestions();
const suggestionsTransform = (value: string, suggestions: TagType[]) => (
suggestions.filter((tag: TagType) => value && tag.label.search(value) >= 0)
suggestions.filter((tag: TagType) => value && tag.label && tag.label.search(value) >= 0)
);

const context = useEditContext();
Expand Down
3 changes: 2 additions & 1 deletion packages/bodiless-next/src/getStaticPaths.ts
Expand Up @@ -21,6 +21,7 @@ import type { AliasItem } from '@bodiless/page';
import { hasTrailingSlash } from './nextConfig';

const getStaticPaths = async () => {
const isEdit = process.env.NODE_ENV === 'development';
const pages = await getPages();
const disablePageList = getDisabledPages();
const disabledPages = Object.keys(disablePageList).filter(
Expand Down Expand Up @@ -49,7 +50,7 @@ const getStaticPaths = async () => {
}
}))
],
fallback: false,
fallback: isEdit ? 'blocking' : false,
};
};

Expand Down
24 changes: 17 additions & 7 deletions packages/bodiless-next/src/getStaticProps.ts
Expand Up @@ -16,7 +16,8 @@ import {
findComponentPath,
findSubPageTemplateTemplate,
findTemplate,
getRedirectAliases
getRedirectAliases,
getPages
} from '@bodiless/page/lib/cjs/NodeApi';
import { createGitInfo } from '@bodiless/git/lib/cjs/NodeApi';
import path from 'path';
Expand Down Expand Up @@ -122,14 +123,17 @@ const loadDataFromFiles = async (filepath :string, publicPath: string) => {
};

const getStaticProps = async ({ params }: getServerSideProps) => {
const redirects = redirectsCache.get('redirects') || getRedirectAliases();
const isEdit = process.env.NODE_ENV === 'development';
const redirects = isEdit ? getRedirectAliases() : redirectsCache.get('redirects') || getRedirectAliases();
redirectsCache.set('redirects', redirects);

const { slug = [''] } = params;

const slugString = `/${slug.join('/')}`;

const redirect = redirects.filter((redirect: AliasItem) => redirect.fromPath === slugString);
const realSlug = hasTrailingSlash() ? `${slugString}/`.replace('//', '/') : slugString;

const redirect = redirects.filter((redirect: AliasItem) => redirect.fromPath === realSlug);

// If the page is a redirect meta returns the minimal info
if (redirect.length) {
Expand All @@ -142,8 +146,6 @@ const getStaticProps = async ({ params }: getServerSideProps) => {
const defaultContentSources = [];
const gitInfo = await createGitInfo();

const realSlug = hasTrailingSlash() ? `${slugString}/`.replace('//', '/') : slugString;

const templateBasePath = ['.', 'src', 'templates'];
const pagesBasePath = ['.', 'src', 'data', 'pages'];
const siteDataBasePath = ['.', 'src', 'data', 'site'];
Expand All @@ -156,8 +158,8 @@ const getStaticProps = async ({ params }: getServerSideProps) => {
},
data: {
Page: [],
Site: propsCache.get('pageDataSite') || [],
DefaultContent: propsCache.get('pageDataDefaultContent') || [],
Site: isEdit ? [] : propsCache.get('pageDataSite') || [],
DefaultContent: isEdit ? [] : propsCache.get('pageDataDefaultContent') || [],
},
};

Expand Down Expand Up @@ -218,6 +220,14 @@ const getStaticProps = async ({ params }: getServerSideProps) => {
console.warn(`Error trying to create ${pageData.path}`, exception);
}

if (isEdit) {
const pages = await getPages();
if (!pages.includes(slugString === '/' ? '' : slugString)) {
return {
notFound: true
};
}
}
return {
props: pageData,
};
Expand Down
32 changes: 6 additions & 26 deletions packages/bodiless-page/src/Operations/PageVerification.ts
Expand Up @@ -16,45 +16,25 @@ import axios from 'axios';
import sleep from 'sleep-promise';
import { PageProps } from '../types';

const stripSurroundingSlashes = (path: string): string => {
let path$ = path[0] === '/' ? path.slice(1) : path;
path$ = path$.endsWith('/') ? path$.slice(0, -1) : path$;
return path$;
};

const createPageDataUrl = (path: string) => {
const fixedPath = path === '/' ? 'index' : stripSurroundingSlashes(path);
return `/page-data/${fixedPath}/page-data.json`;
};

const doFetch = (url: string) => axios.get(url, {
// resolve promise for all HTTP response status codes
// so that can get more control on retry logic
validateStatus: () => true,
});

const loadPageDataJson = (loadObj: PageProps): Promise<boolean> => {
const loadPage = (loadObj: PageProps): Promise<boolean> => {
const { pagePath, retries = 0 } = loadObj;
const url = createPageDataUrl(pagePath);
return doFetch(url).then(req => {
const { status, data } = req;
return doFetch(pagePath).then(req => {
const { status } = req;
// Handle 200
if (status === 200) {
try {
if (data.path === undefined) {
throw new Error('not a valid pageData response');
}

return true;
} catch (err) {
// continue regardless of error
}
return true;
}

// Handle everything else, including status === 0, and 503s. Should retry
if (retries < 5) {
return sleep(2000)
.then(() => loadPageDataJson(Object.assign(loadObj, { retries: retries + 1 })));
.then(() => loadPage(Object.assign(loadObj, { retries: retries + 1 })));
}

// Retried 5 times already, result is a failure.
Expand All @@ -63,7 +43,7 @@ const loadPageDataJson = (loadObj: PageProps): Promise<boolean> => {
};

const verifyPage = (pagePath: string): Promise<boolean> => sleep(2000)
.then(() => loadPageDataJson({ pagePath }));
.then(() => loadPage({ pagePath }));

export {
verifyPage,
Expand Down
4 changes: 2 additions & 2 deletions packages/bodiless-page/src/RedirectAlias/form.tsx
Expand Up @@ -157,7 +157,6 @@ const FormBodyBase = () => {
aliases: initialAliases,
isValid: true,
};

setValues(values);
}, []);
const { next } = useMultistepApi();
Expand All @@ -166,7 +165,7 @@ const FormBodyBase = () => {
const { values: formValues } = getFormState();

// @ts-ignore
const { Edit: { aliases} } = formValues;
const { Edit: { aliases = ''} = {} } = formValues;

if (!isTextValid(aliases as string)) {
setValue('isValid', false);
Expand All @@ -189,6 +188,7 @@ const FormBodyBase = () => {
name="aliases"
onFocus={() => setValue('isValid', true)}
placeholder={REDIRECT_ALIASES_PLACEHOLDER}
initialValue={initialAliases}
/>
<ComponentFormIsValid keepState name="isValid" />
<i>{ !formValues.isValid && INVALIDATED }</i>
Expand Down
2 changes: 1 addition & 1 deletion sites/vital-demo-next/next.config.js
Expand Up @@ -15,7 +15,7 @@ module.exports = {
const options = {
enabled: process.env.BODILESS_BUILD_STATS === '1',
sitePath: process.env.BODILESS_STATS_PATH || path.resolve('./public/generated'),
name: 'vita-demo-next',
name: 'vital-demo-next',
open: process.env.BODILESS_OPEN_STATS === '1' ? 'file' : false,
};

Expand Down