mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-01-24 13:45:07 +08:00
feat(renderer): page rendering, incomplete
This commit is contained in:
parent
7e2e2048ef
commit
a91fadf166
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Block from './Block';
|
||||
|
||||
const AutoBlock = ({ page }) => {
|
||||
return (
|
||||
<>
|
||||
{page.blocks.map((block) => {
|
||||
return <Block key={block.id} meta={block.meta} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoBlock;
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connectBlock } from '@lowdefy/block-tools';
|
||||
import useDynamicScript from './utils/useDynamicScript';
|
||||
import loadComponent from './utils/loadComponent';
|
||||
|
||||
const Comp = ({ bl }) => {
|
||||
const CBlock = connectBlock(bl);
|
||||
return <CBlock />;
|
||||
};
|
||||
|
||||
function Block({ meta }) {
|
||||
const { ready, failed } = useDynamicScript({
|
||||
url: meta && meta.url,
|
||||
});
|
||||
|
||||
if (!meta) {
|
||||
return <h2>Not meta specified</h2>;
|
||||
}
|
||||
|
||||
if (!ready) {
|
||||
return <h2>Loading dynamic script: {meta.url}</h2>;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
return <h2>Failed to load dynamic script: {meta.url}</h2>;
|
||||
}
|
||||
|
||||
const Component = React.lazy(loadComponent(meta.scope, meta.module));
|
||||
|
||||
return (
|
||||
<React.Suspense fallback="Loading Block">
|
||||
<Comp bl={Component} />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Block;
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { gql } from '@apollo/client';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import AutoBlock from './AutoBlock';
|
||||
|
||||
const GET_PAGE = gql`
|
||||
query page($pageId: ID!) {
|
||||
page(pageId: $pageId)
|
||||
}
|
||||
`;
|
||||
|
||||
const Page = () => {
|
||||
const { loading, error, data } = useQuery(GET_PAGE, {
|
||||
variables: {
|
||||
pageId: 'page1',
|
||||
},
|
||||
});
|
||||
if (loading) return <h2>Loading</h2>;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return <h2>Error</h2>;
|
||||
}
|
||||
console.log('data', data);
|
||||
return <AutoBlock page={data.page} />;
|
||||
};
|
||||
|
||||
export default Page;
|
@ -22,7 +22,7 @@ import { ErrorBoundary } from '@lowdefy/block-tools';
|
||||
import get from '@lowdefy/get';
|
||||
|
||||
import useGqlClient from './utils/graphql/useGqlClient';
|
||||
import PageContext from './PageContext';
|
||||
import PageContext from './page/PageContext';
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const windowContext = window;
|
||||
|
133
packages/renderer/src/page/AutoBlock.js
Normal file
133
packages/renderer/src/page/AutoBlock.js
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { BlockLayout } from '@lowdefy/layout';
|
||||
import { makeContextId } from '@lowdefy/engine';
|
||||
import { makeCssClass } from '@lowdefy/block-tools';
|
||||
|
||||
import Container from './Container';
|
||||
import Context from './Context';
|
||||
import List from './List';
|
||||
|
||||
const AutoBlock = ({ block, Blocks, Component, context, pageId, rootContext }) => {
|
||||
switch (block.meta.category) {
|
||||
case 'context':
|
||||
return (
|
||||
<Context
|
||||
block={block}
|
||||
Component={Component}
|
||||
context={context}
|
||||
contextId={makeContextId({
|
||||
branch: rootContext.branch,
|
||||
urlQuery: rootContext.urlQuery,
|
||||
pageId,
|
||||
blockId: block.blockId,
|
||||
})}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
);
|
||||
case 'list':
|
||||
return (
|
||||
<List
|
||||
block={block}
|
||||
Blocks={Blocks}
|
||||
Component={Component}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
);
|
||||
case 'container':
|
||||
return (
|
||||
<Container
|
||||
block={block}
|
||||
Blocks={Blocks}
|
||||
Component={Component}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
);
|
||||
case 'input':
|
||||
return (
|
||||
<BlockLayout
|
||||
id={`bl-${block.blockId}`}
|
||||
blockStyle={block.eval.style}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
layout={block.eval.layout || {}}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
methods={{
|
||||
callAction: block.callAction,
|
||||
makeCssClass,
|
||||
registerAction: block.registerAction,
|
||||
registerMethod: block.registerMethod,
|
||||
setValue: block.setValue,
|
||||
}}
|
||||
actions={block.eval.actions}
|
||||
blockId={block.blockId}
|
||||
Components={rootContext.Components}
|
||||
homePageId={rootContext.homePageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={rootContext.menus}
|
||||
pageId={pageId}
|
||||
properties={block.eval.properties}
|
||||
required={block.eval.required}
|
||||
user={rootContext.user}
|
||||
validate={block.eval.validate}
|
||||
value={block.value}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<BlockLayout
|
||||
id={`bl-${block.blockId}`}
|
||||
blockStyle={block.eval.style}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
layout={block.eval.layout || {}}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
methods={{
|
||||
callAction: block.callAction,
|
||||
makeCssClass,
|
||||
registerAction: block.registerAction,
|
||||
registerMethod: block.registerMethod,
|
||||
}}
|
||||
actions={block.eval.actions}
|
||||
blockId={block.blockId}
|
||||
Components={rootContext.Components}
|
||||
homePageId={rootContext.homePageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={rootContext.menus}
|
||||
pageId={pageId}
|
||||
properties={block.eval.properties}
|
||||
required={block.eval.required}
|
||||
user={rootContext.user}
|
||||
validate={block.eval.validate}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AutoBlock;
|
85
packages/renderer/src/page/BindAutoBlock.js
Normal file
85
packages/renderer/src/page/BindAutoBlock.js
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Suspense } from 'react';
|
||||
import { useQuery, gql } from '@apollo/client';
|
||||
import { Loading, makeCssClass, connectBlock, ErrorBoundary } from '@lowdefy/block-tools';
|
||||
|
||||
import AutoBlock from './AutoBlock';
|
||||
import prepareBlock from './prepareBlock';
|
||||
|
||||
const getBlock = gql`
|
||||
query getBlock($id: String!) {
|
||||
block(id: $id) @client {
|
||||
id
|
||||
t
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const BindAutoBlock = ({ block, Blocks, context, pageId, rootContext }) => {
|
||||
const { loading, error, data } = useQuery(getBlock, {
|
||||
variables: {
|
||||
id: `BlockClass:${block.id}`,
|
||||
},
|
||||
client: rootContext.client,
|
||||
});
|
||||
|
||||
if (loading) return 'Loading render watcher';
|
||||
if (error) throw error;
|
||||
if (block.eval.visible === false)
|
||||
return <div id={`vs-${block.blockId}`} style={{ display: 'none' }} />;
|
||||
|
||||
const Component = prepareBlock({
|
||||
block,
|
||||
Components: rootContext.Components,
|
||||
});
|
||||
|
||||
if (data.block.loading) {
|
||||
return (
|
||||
<Loading
|
||||
id={`lo-${block.blockId}-loading`}
|
||||
meta={block.meta}
|
||||
methods={{ makeCssClass }}
|
||||
blockStyle={block.eval.style || {}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<Loading
|
||||
id={`sp-${block.blockId}-loading`}
|
||||
meta={block.meta}
|
||||
methods={{ makeCssClass }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<AutoBlock
|
||||
block={block}
|
||||
Blocks={Blocks}
|
||||
Component={connectBlock(Component)}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
export default BindAutoBlock;
|
89
packages/renderer/src/page/Container.js
Normal file
89
packages/renderer/src/page/Container.js
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Area, BlockLayout, layoutParamsToArea } from '@lowdefy/layout';
|
||||
import { connectBlock, makeCssClass } from '@lowdefy/block-tools';
|
||||
|
||||
import BindAutoBlock from './BindAutoBlock';
|
||||
|
||||
const ConnectedArea = connectBlock(Area);
|
||||
|
||||
const Container = ({ block, Blocks, Component, context, pageId, rootContext }) => {
|
||||
const content = {};
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
const areas = Blocks.subBlocks[block.id][0].areas;
|
||||
Object.keys(areas).forEach((areaKey) => {
|
||||
content[areaKey] = (areaStyle) => (
|
||||
<ConnectedArea
|
||||
id={`ar-${block.blockId}-${areaKey}`}
|
||||
key={`ar-${block.blockId}-${areaKey}`}
|
||||
area={layoutParamsToArea({
|
||||
area: block.eval.areas[areaKey] || {},
|
||||
areaKey,
|
||||
layout: block.eval.layout || {},
|
||||
})}
|
||||
areaStyle={[areaStyle, block.eval.areas[areaKey] && block.eval.areas[areaKey].style]}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
{areas[areaKey].blocks.map((bl) => (
|
||||
<BindAutoBlock
|
||||
key={`co-${bl.blockId}`}
|
||||
Blocks={Blocks.subBlocks[block.id][0]}
|
||||
block={bl}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
))}
|
||||
</ConnectedArea>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<BlockLayout
|
||||
id={`bl-${block.blockId}`}
|
||||
blockStyle={block.eval.style}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
layout={block.eval.layout || {}}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
methods={{
|
||||
callAction: block.callAction,
|
||||
makeCssClass,
|
||||
registerAction: block.registerAction,
|
||||
registerMethod: block.registerMethod,
|
||||
}}
|
||||
actions={block.eval.actions}
|
||||
blockId={block.blockId}
|
||||
Components={rootContext.Components}
|
||||
content={content}
|
||||
homePageId={rootContext.homePageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={rootContext.menus}
|
||||
pageId={pageId}
|
||||
properties={block.eval.properties}
|
||||
required={block.eval.required}
|
||||
user={rootContext.user}
|
||||
validate={block.eval.validate}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Container;
|
48
packages/renderer/src/page/Context.js
Normal file
48
packages/renderer/src/page/Context.js
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Loading, makeCssClass } from '@lowdefy/block-tools';
|
||||
|
||||
import useContext from './useContext';
|
||||
import Container from './Container';
|
||||
|
||||
const Context = ({ block, Component, pageId, rootContext, contextId }) => {
|
||||
const { context, loading, error } = useContext({ block, pageId, rootContext, contextId });
|
||||
if (loading) {
|
||||
return (
|
||||
<Loading
|
||||
meta={block.meta}
|
||||
methods={{ makeCssClass }}
|
||||
blockStyle={(block.eval && block.eval.style) || block.style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) throw error;
|
||||
return (
|
||||
<Container
|
||||
block={context.RootBlocks.areas.root.blocks[0]}
|
||||
Blocks={context.RootBlocks}
|
||||
Component={Component}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Context;
|
37
packages/renderer/src/page/Helmet.js
Normal file
37
packages/renderer/src/page/Helmet.js
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
const BindHelmet = ({ pageProperties }) => {
|
||||
return (
|
||||
<Helmet>
|
||||
<meta charSet="utf-8" />
|
||||
<title>{pageProperties.title}</title>
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
href={
|
||||
pageProperties.faviconPath
|
||||
? `%PUBLIC_URL%/${pageProperties.faviconPath}`
|
||||
: '%PUBLIC_URL%/favicon.ico'
|
||||
}
|
||||
/>
|
||||
</Helmet>
|
||||
);
|
||||
};
|
||||
|
||||
export default BindHelmet;
|
96
packages/renderer/src/page/List.js
Normal file
96
packages/renderer/src/page/List.js
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Area, BlockLayout, layoutParamsToArea } from '@lowdefy/layout';
|
||||
import { connectBlock, makeCssClass } from '@lowdefy/block-tools';
|
||||
|
||||
import BindAutoBlock from './BindAutoBlock';
|
||||
|
||||
const ConnectedArea = connectBlock(Area);
|
||||
|
||||
const List = ({ block, Blocks, Component, context, pageId, rootContext }) => {
|
||||
const content = {};
|
||||
const contentList = [];
|
||||
Blocks.subBlocks[block.id].forEach((SBlock) => {
|
||||
Object.keys(SBlock.areas).forEach((areaKey) => {
|
||||
content[areaKey] = (areaStyle) => (
|
||||
<ConnectedArea
|
||||
id={`ar-${block.blockId}-${SBlock.id}-${areaKey}`}
|
||||
key={`ar-${block.blockId}-${SBlock.id}-${areaKey}`}
|
||||
area={layoutParamsToArea({
|
||||
area: block.eval.areas[areaKey] || {},
|
||||
areaKey,
|
||||
layout: block.eval.layout || {},
|
||||
})}
|
||||
areaStyle={[areaStyle, block.eval.areas[areaKey] && block.eval.areas[areaKey].style]}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
{SBlock.areas[areaKey].blocks.map((bl) => (
|
||||
<BindAutoBlock
|
||||
key={`ls-${bl.blockId}`}
|
||||
Blocks={SBlock}
|
||||
block={bl}
|
||||
context={context}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
))}
|
||||
</ConnectedArea>
|
||||
);
|
||||
});
|
||||
contentList.push({ ...content });
|
||||
});
|
||||
return (
|
||||
<BlockLayout
|
||||
id={`bl-${block.blockId}`}
|
||||
blockStyle={block.eval.style}
|
||||
highlightBorders={rootContext.lowdefyGlobal.highlightBorders}
|
||||
layout={block.eval.layout || {}}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
methods={{
|
||||
callAction: block.callAction,
|
||||
makeCssClass,
|
||||
moveItemDown: block.moveItemDown,
|
||||
moveItemUp: block.moveItemUp,
|
||||
pushItem: block.pushItem,
|
||||
registerAction: block.registerAction,
|
||||
registerMethod: block.registerMethod,
|
||||
removeItem: block.removeItem,
|
||||
unshiftItem: block.unshiftItem,
|
||||
}}
|
||||
actions={block.eval.actions}
|
||||
blockId={block.blockId}
|
||||
Components={rootContext.Components}
|
||||
content={contentList}
|
||||
homePageId={rootContext.homePageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={rootContext.menus}
|
||||
pageId={pageId}
|
||||
properties={block.eval.properties}
|
||||
required={block.eval.required}
|
||||
user={rootContext.user}
|
||||
validate={block.eval.validate}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default List;
|
84
packages/renderer/src/page/PageContext.js
Normal file
84
packages/renderer/src/page/PageContext.js
Normal file
@ -0,0 +1,84 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Suspense } from 'react';
|
||||
import { useParams, useHistory, useLocation, Redirect } from 'react-router-dom';
|
||||
import { useQuery, gql } from '@apollo/client';
|
||||
|
||||
import { Loading, connectBlock } from '@lowdefy/block-tools';
|
||||
import get from '@lowdefy/get';
|
||||
import { urlQuery } from '@lowdefy/helpers';
|
||||
|
||||
import AutoBlock from './AutoBlock';
|
||||
import Helmet from './Helmet';
|
||||
import prepareBlock from './prepareBlock';
|
||||
|
||||
const GET_PAGE = gql`
|
||||
query getPage($id: ID!) {
|
||||
page(pageId: $id)
|
||||
}
|
||||
`;
|
||||
|
||||
const PageContext = ({ rootContext }) => {
|
||||
const { pageId } = useParams();
|
||||
rootContext.routeHistory = useHistory();
|
||||
const { search } = useLocation();
|
||||
rootContext.urlQuery = urlQuery.parse(search || '');
|
||||
const { loading, error, data } = useQuery(GET_PAGE, {
|
||||
variables: { id: pageId, branch: rootContext.branch },
|
||||
});
|
||||
if (loading) {
|
||||
console.log('loading');
|
||||
return Loading;
|
||||
}
|
||||
// if (error) throw error;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return <div>Error</div>;
|
||||
}
|
||||
console.log('finished loading');
|
||||
// redirect 404
|
||||
if (!data.page) return <Redirect to="/404" />;
|
||||
|
||||
console.log('data', data.page);
|
||||
const Component = prepareBlock({
|
||||
block: data.page,
|
||||
Components: rootContext.Components,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet pageProperties={get(data.page, 'properties', { default: {} })} />
|
||||
<div>Hello</div>
|
||||
<div id={pageId}>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<AutoBlock
|
||||
block={data.page}
|
||||
Blocks={null}
|
||||
Component={connectBlock(Component)}
|
||||
context={null}
|
||||
pageId={pageId}
|
||||
rootContext={rootContext}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageContext;
|
38
packages/renderer/src/page/prepareBlock.js
Normal file
38
packages/renderer/src/page/prepareBlock.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { lazy } from 'react';
|
||||
import useDynamicScript from '../utils/useDynamicScript';
|
||||
import loadComponent from '../utils/loadComponent';
|
||||
|
||||
const prepareBlock = ({ Components, block }) => {
|
||||
const componentId = `${block.meta.scope}:${block.meta.module}`;
|
||||
const { ready, failed } = useDynamicScript({
|
||||
url: block.meta.url,
|
||||
});
|
||||
if (!Components[componentId]) {
|
||||
if (!ready) {
|
||||
return <h2>Loading dynamic script: {block.meta.url}</h2>;
|
||||
}
|
||||
if (failed) {
|
||||
return <h2>Failed to load dynamic script: {block.meta.url}</h2>;
|
||||
}
|
||||
Components[componentId] = lazy(loadComponent(block.meta.scope, block.meta.module));
|
||||
}
|
||||
return Components[componentId];
|
||||
};
|
||||
|
||||
export default prepareBlock;
|
90
packages/renderer/src/page/useContext.js
Normal file
90
packages/renderer/src/page/useContext.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
// import { message, notification } from 'antd';
|
||||
import getContext from '@lowdefy/engine';
|
||||
|
||||
// message.config({
|
||||
// duration: 4,
|
||||
// maxCount: 12,
|
||||
// });
|
||||
// notification.config({
|
||||
// placement: 'bottomRight',
|
||||
// bottom: 50,
|
||||
// duration: 5,
|
||||
// });
|
||||
|
||||
const message = {
|
||||
loading: (message) => console.log(message),
|
||||
error: (message) => console.log(message),
|
||||
success: (message) => console.log(message),
|
||||
};
|
||||
|
||||
const notification = {
|
||||
loading: (message) => console.log(message),
|
||||
error: (message) => console.log(message),
|
||||
success: (message) => console.log(message),
|
||||
};
|
||||
|
||||
const onEnter = (context) => {
|
||||
return context.RootBlocks.areas.root.blocks[0].callAction({
|
||||
action: 'onEnter',
|
||||
hideLoading: true,
|
||||
});
|
||||
};
|
||||
|
||||
const fetchAll = (context) => {
|
||||
// fetch all new requests on page
|
||||
return context.Requests.callRequests({
|
||||
onlyNew: true,
|
||||
});
|
||||
};
|
||||
|
||||
const useContext = ({ block, pageId, rootContext, contextId }) => {
|
||||
const [error, setError] = useState(null);
|
||||
const [context, setContext] = useState(null);
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
const mount = async () => {
|
||||
try {
|
||||
const ctx = await getContext({
|
||||
block,
|
||||
contextId,
|
||||
pageId,
|
||||
rootContext,
|
||||
message,
|
||||
notification,
|
||||
});
|
||||
if (mounted) await onEnter(ctx);
|
||||
if (mounted) {
|
||||
fetchAll(ctx);
|
||||
setContext(ctx);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
};
|
||||
mount();
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [block, pageId, rootContext, contextId]);
|
||||
|
||||
return { error, context, loading: !context && !error };
|
||||
};
|
||||
|
||||
export default useContext;
|
@ -29,7 +29,7 @@ const cache = new InMemoryCache({
|
||||
});
|
||||
const retryLink = new RetryLink();
|
||||
const httpLink = new HttpLink({
|
||||
uri: '/graphql',
|
||||
uri: '/api/graphql',
|
||||
});
|
||||
|
||||
// TODO: Handle errors
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
/*
|
||||
Copyright 2020 Lowdefy, Inc
|
||||
|
||||
@ -18,7 +20,6 @@ function loadComponent(scope, module) {
|
||||
return async () => {
|
||||
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
|
||||
await __webpack_init_sharing__('default');
|
||||
console.log(window);
|
||||
const container = window[scope]; // or get the container somewhere else
|
||||
// Initialize the container, it may provide shared modules
|
||||
await container.init(__webpack_share_scopes__.default);
|
||||
|
@ -1,5 +1,6 @@
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { ModuleFederationPlugin } = require('webpack').container;
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
|
||||
const deps = require('./package.json').dependencies;
|
||||
@ -14,6 +15,13 @@ module.exports = {
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
// webpack 5 support polyfills
|
||||
resolve: {
|
||||
alias: {
|
||||
buffer: require.resolve('buffer'),
|
||||
},
|
||||
fallback: { buffer: false },
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@ -23,6 +31,15 @@ module.exports = {
|
||||
lazy: true,
|
||||
},
|
||||
},
|
||||
// TODO: FIXME: do NOT webpack 5 support with this
|
||||
// x-ref: https://github.com/webpack/webpack/issues/11467
|
||||
// waiting for babel fix: https://github.com/vercel/next.js/pull/17095#issuecomment-692435147
|
||||
{
|
||||
test: /\.m?js/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
loader: 'babel-loader',
|
||||
@ -65,6 +82,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
}),
|
||||
new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './public/index.html',
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user