feat(build): build connections and menus

This commit is contained in:
Sam Tolmay 2020-10-20 14:32:09 +02:00
parent 3ab2819944
commit 3f4b486459
5 changed files with 621 additions and 0 deletions

View File

@ -0,0 +1,33 @@
/* eslint-disable no-param-reassign */
/*
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 { type } from '@lowdefy/helpers';
async function buildConnections({ components, context }) {
if (type.isArray(components.connections)) {
components.connections.forEach((connection) => {
connection.connectionId = connection.id;
connection.id = `connection:${connection.id}`;
});
}
await context.logger.debug('Built connections');
await context.logger.debug(JSON.stringify(components.connections));
return components;
}
export default buildConnections;

View File

@ -0,0 +1,60 @@
/*
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 buildConnections from './buildConnections';
import testContext from '../test/testContext';
const context = testContext();
test('buildConnections no connections', async () => {
const components = {};
const res = await buildConnections({ components, context });
expect(res.connections).toBe(undefined);
});
test('buildConnections connections not an array', async () => {
const components = {
connections: 'connections',
};
const res = await buildConnections({ components, context });
expect(res).toEqual({
connections: 'connections',
});
});
test('buildConnections', async () => {
const components = {
connections: [
{
id: 'connection1',
},
{
id: 'connection2',
},
],
};
const res = await buildConnections({ components, context });
expect(res.connections).toEqual([
{
id: 'connection:connection1',
connectionId: 'connection1',
},
{
id: 'connection:connection2',
connectionId: 'connection2',
},
]);
});

View File

@ -0,0 +1,87 @@
/* eslint-disable no-param-reassign */
/*
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 { type } from '@lowdefy/helpers';
async function buildDefaultMenu({ components, context }) {
context.logger.warn('No menus found. Building default menu.');
const pages = type.isArray(components.pages) ? components.pages : [];
const menus = [
{
id: 'default',
links: pages.map((page, i) => ({
id: `${i}`,
type: 'MenuLink',
pageId: page.pageId,
})),
},
];
return menus;
}
function loopItems(parent, menuId, pages, missingPageWarnings) {
if (type.isArray(parent.links)) {
parent.links.forEach((menuItem) => {
if (menuItem.type === 'MenuLink') {
if (type.isString(menuItem.pageId)) {
const page = pages.find((pg) => pg.pageId === menuItem.pageId);
if (!page) {
missingPageWarnings.push({
menuItemId: menuItem.id,
pageId: menuItem.pageId,
});
// remove menuItem from menu
menuItem.remove = true;
return;
}
}
}
menuItem.menuItemId = menuItem.id;
menuItem.id = `menuitem:${menuId}:${menuItem.id}`;
loopItems(menuItem, menuId, pages, missingPageWarnings);
});
parent.links = parent.links.filter((item) => item.remove !== true);
}
}
async function buildMenu({ components, context }) {
const pages = type.isArray(components.pages) ? components.pages : [];
if (type.isUndefined(components.menus) || components.menus.length === 0) {
components.menus = await buildDefaultMenu({ components, context });
}
const missingPageWarnings = [];
components.menus.forEach((menu) => {
menu.menuId = menu.id;
menu.id = `menu:${menu.id}`;
loopItems(menu, menu.menuId, pages, missingPageWarnings);
});
await Promise.all(
missingPageWarnings.map(async (warning) => {
await context.logger.warn(
`Page ${warning.pageId} referenced in menu link ${warning.menuItemId} not found.`
);
})
);
await context.logger.debug('Built menus');
await context.logger.debug(JSON.stringify(components.menus));
return components;
}
export default buildMenu;

View File

@ -0,0 +1,408 @@
/*
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 buildMenu from './buildMenu';
import testContext from '../test/testContext';
const mockLogWarn = jest.fn();
const logger = {
warn: mockLogWarn,
};
const context = testContext({ logger });
beforeEach(() => {
mockLogWarn.mockReset();
});
test('buildMenu menus exist', async () => {
const components = {
menus: [
{
id: 'my_menu',
links: [
{
id: 'menu_page_1',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
pageId: 'page_1',
},
{
id: 'menu_external',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
url: 'www.lowdefy.com',
},
],
},
],
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
],
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:my_menu',
menuId: 'my_menu',
links: [
{
id: 'menuitem:my_menu:menu_page_1',
menuItemId: 'menu_page_1',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
pageId: 'page_1',
},
{
id: 'menuitem:my_menu:menu_external',
menuItemId: 'menu_external',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
url: 'www.lowdefy.com',
},
],
},
],
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
],
});
});
test('buildMenu nested menus', async () => {
const components = {
menus: [
{
id: 'my_menu',
links: [
{
id: 'group',
type: 'MenuGroup',
links: [
{
id: 'menu_page_1',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
pageId: 'page_1',
},
],
},
],
},
],
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
],
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:my_menu',
menuId: 'my_menu',
links: [
{
id: 'menuitem:my_menu:group',
menuItemId: 'group',
type: 'MenuGroup',
links: [
{
id: 'menuitem:my_menu:menu_page_1',
menuItemId: 'menu_page_1',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
pageId: 'page_1',
},
],
},
],
},
],
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
],
});
});
test('buildMenu default menu', async () => {
const components = {
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
{
id: 'page:page_2',
pageId: 'page_2',
},
{
id: 'page:page_3',
pageId: 'page_3',
},
],
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:default',
menuId: 'default',
links: [
{
id: 'menuitem:default:0',
menuItemId: '0',
type: 'MenuLink',
pageId: 'page_1',
},
{
id: 'menuitem:default:1',
menuItemId: '1',
type: 'MenuLink',
pageId: 'page_2',
},
{
id: 'menuitem:default:2',
menuItemId: '2',
type: 'MenuLink',
pageId: 'page_3',
},
],
},
],
pages: [
{
id: 'page:page_1',
pageId: 'page_1',
},
{
id: 'page:page_2',
pageId: 'page_2',
},
{
id: 'page:page_3',
pageId: 'page_3',
},
],
});
});
test('buildMenu no menu or pages exist', async () => {
const components = {};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:default',
menuId: 'default',
links: [],
},
],
});
});
test('buildMenu page does not exist', async () => {
const components = {
menus: [
{
id: 'my_menu',
links: [
{
id: 'menu_page_1',
type: 'MenuLink',
pageId: 'page_1',
},
],
},
],
pages: [],
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:my_menu',
menuId: 'my_menu',
links: [],
},
],
pages: [],
});
expect(mockLogWarn.mock.calls).toEqual([
['Page page_1 referenced in menu link menu_page_1 not found.'],
]);
});
test('buildMenu page does not exist, nested', async () => {
const components = {
menus: [
{
id: 'my_menu',
links: [
{
id: 'MenuGroup1',
type: 'MenuGroup',
links: [
{
id: 'menu_page_1',
type: 'MenuLink',
pageId: 'page_1',
},
],
},
{
id: 'MenuGroup2',
type: 'MenuGroup',
links: [
{
id: 'MenuGroup3',
type: 'MenuGroup',
links: [
{
id: 'menu_page_2',
type: 'MenuLink',
pageId: 'page_2',
},
],
},
],
},
],
},
],
pages: [],
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:my_menu',
menuId: 'my_menu',
links: [
{
id: 'menuitem:my_menu:MenuGroup1',
menuItemId: 'MenuGroup1',
type: 'MenuGroup',
links: [],
},
{
id: 'menuitem:my_menu:MenuGroup2',
menuItemId: 'MenuGroup2',
type: 'MenuGroup',
links: [
{
id: 'menuitem:my_menu:MenuGroup3',
menuItemId: 'MenuGroup3',
type: 'MenuGroup',
links: [],
},
],
},
],
},
],
pages: [],
});
expect(mockLogWarn.mock.calls).toEqual([
['Page page_1 referenced in menu link menu_page_1 not found.'],
['Page page_2 referenced in menu link menu_page_2 not found.'],
]);
});
test('buildMenu pages not array, menu exists', async () => {
const components = {
menus: [
{
id: 'my_menu',
links: [
{
id: 'menu_external',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
url: 'www.lowdefy.com',
},
],
},
],
pages: 'pages',
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:my_menu',
menuId: 'my_menu',
links: [
{
id: 'menuitem:my_menu:menu_external',
menuItemId: 'menu_external',
properties: {
title: 'Page 1',
},
type: 'MenuLink',
url: 'www.lowdefy.com',
},
],
},
],
pages: 'pages',
});
});
test('buildMenu pages not array, no menu', async () => {
const components = {
pages: 'pages',
};
const res = await buildMenu({ components, context });
expect(res).toEqual({
menus: [
{
id: 'menu:default',
menuId: 'default',
links: [],
},
],
pages: 'pages',
});
});

View File

@ -0,0 +1,33 @@
function testContext({ logger = {}, configLoader, artifactSetter } = {}) {
const defaultLogger = {
success: () => {},
warn: () => {},
error: () => {},
debug: () => {},
};
const context = {
configLoader: {
load: () => {},
},
artifactSetter: {
set: () => [],
},
};
context.logger = {
...defaultLogger,
...logger,
};
if (configLoader) {
context.configLoader = configLoader;
}
if (artifactSetter) {
context.artifactSetter = artifactSetter;
}
return context;
}
export default testContext;