mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-08-09 07:25:21 +02:00
fix: change the method to group of pages
This commit is contained in:
parent
8a7242d364
commit
45d9e501d2
6 changed files with 159 additions and 61 deletions
|
@ -1,5 +1,7 @@
|
|||
import Page, { PageData } from '../models/page';
|
||||
import Alias from '../models/alias';
|
||||
import PagesOrder from './pagesOrder';
|
||||
import PageOrder from '../models/pageOrder';
|
||||
|
||||
type PageDataFields = keyof PageData;
|
||||
|
||||
|
@ -63,59 +65,99 @@ class Pages {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sort given pages with descending order of creation time
|
||||
* Group all pages by their parents
|
||||
* If the pageId is passed, it excludes passed page from result pages
|
||||
*
|
||||
* @param {pages[]} pages - pages to sort
|
||||
* @returns {page[]}
|
||||
*/
|
||||
public static sortByTimeDesc(pages: Page[]): Page[] {
|
||||
return pages.sort((a, b) => {
|
||||
if (a.body.time > b.body.time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.body.time < b.body.time) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Group given pages by their parents
|
||||
*
|
||||
* @param {pages[]} pages - pages to group
|
||||
* @param {string} pageId - pageId to exclude from result pages
|
||||
* @returns {Page[]}
|
||||
*/
|
||||
public static groupByParent(pages: Page[]): Page[] {
|
||||
public static async groupByParent(pageId = ''): Promise<Page[]> {
|
||||
const result: Page[] = [];
|
||||
const pagesGroupedByParent:Record<string, Array<Page>> = {};
|
||||
|
||||
pages.forEach(page => {
|
||||
pagesGroupedByParent[String(page._id)] = [];
|
||||
|
||||
if (this.isRootPage(page)) {
|
||||
pagesGroupedByParent[String(page._id)].push(page);
|
||||
} else {
|
||||
pagesGroupedByParent[String(page._parent)].push(page);
|
||||
}
|
||||
});
|
||||
const orderGroupedByParent: Record<string, string[]> = {};
|
||||
const rootPageOrder = await PagesOrder.getRootPageOrder();
|
||||
const childPageOrder = await PagesOrder.getChildPageOrder();
|
||||
const orphanPageOrder: PageOrder[] = [];
|
||||
|
||||
/**
|
||||
* It converts grouped object to array
|
||||
* Also removes redundant keys when there is no children
|
||||
* If there is no root nad child page order, then it returns empty array
|
||||
*/
|
||||
Object.entries(pagesGroupedByParent).forEach(([, value]) => {
|
||||
if (value.length <= 0) {
|
||||
return;
|
||||
} else {
|
||||
result.push(...value);
|
||||
}
|
||||
});
|
||||
if (!rootPageOrder || (!rootPageOrder && childPageOrder.length <= 0)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return result;
|
||||
const pages = (await this.getAll()).reduce((map, _page) => {
|
||||
map.set(_page._id, _page);
|
||||
|
||||
return map;
|
||||
}, new Map);
|
||||
const rootPagesId = rootPageOrder.order;
|
||||
|
||||
/**
|
||||
* It groups root pages and 1 level pages by its parent
|
||||
*/
|
||||
rootPagesId.reduce((prev, curr, idx) => {
|
||||
const childPages = childPageOrder.filter((child, _idx) => {
|
||||
if (child.page === curr) {
|
||||
childPageOrder.splice(_idx, 1);
|
||||
|
||||
return child;
|
||||
}
|
||||
});
|
||||
const hasChildPage = childPages.length > 0;
|
||||
|
||||
if (hasChildPage) {
|
||||
prev[curr] = [];
|
||||
prev[curr].push(curr);
|
||||
prev[curr].push(...childPages[0].order);
|
||||
} else {
|
||||
prev[curr] = [];
|
||||
prev[curr].push(curr);
|
||||
}
|
||||
|
||||
if (idx === rootPagesId.length - 1 && childPageOrder.length > 0) {
|
||||
orphanPageOrder.push(...childPageOrder);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, orderGroupedByParent);
|
||||
|
||||
/**
|
||||
* It groups remained ungrouped pages by its parent
|
||||
*/
|
||||
while (orphanPageOrder.length > 0) {
|
||||
orphanPageOrder.forEach((orphanOrder, idx) => {
|
||||
Object.entries(orderGroupedByParent).forEach(([key, value]) => {
|
||||
if (orphanOrder.page && orphanOrder.order && value.includes(orphanOrder.page)) {
|
||||
orderGroupedByParent[key].splice(value.indexOf(orphanOrder.page) + 1, 0, ...orphanOrder.order);
|
||||
orphanPageOrder.splice(idx, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* It converts grouped pages(object) to array
|
||||
*/
|
||||
Object.values(orderGroupedByParent).flatMap(arr => [ ...arr ])
|
||||
.forEach(arr => {
|
||||
result.push(pages.get(arr));
|
||||
});
|
||||
|
||||
/**
|
||||
* If the pageId passed, it excludes itself from result pages
|
||||
* Otherwise just returns result itself
|
||||
*/
|
||||
if (pageId) {
|
||||
return this.removeChildren(result, pageId).reduce((prev, curr) => {
|
||||
if (curr instanceof Page) {
|
||||
prev.push(curr);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, Array<Page>());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +167,7 @@ class Pages {
|
|||
* @param {string} parent - id of parent page
|
||||
* @returns {Array<?Page>}
|
||||
*/
|
||||
public static removeChildren(pagesAvailable: Array<Page|null>, parent: string | undefined): Array<Page | null> {
|
||||
public static removeChildren(pagesAvailable: Array<Page | null>, parent: string | undefined): Array<Page | null> {
|
||||
pagesAvailable.forEach(async (item, index) => {
|
||||
if (item === null || item._parent !== parent) {
|
||||
return;
|
||||
|
@ -259,16 +301,6 @@ class Pages {
|
|||
throw new Error('Please, fill page Header');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given page is root
|
||||
*
|
||||
* @param {page} page - page to check
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isRootPage(page:Page):boolean {
|
||||
return page._parent === '0';
|
||||
}
|
||||
}
|
||||
|
||||
export default Pages;
|
||||
|
|
|
@ -33,6 +33,24 @@ class PagesOrder {
|
|||
return PageOrder.getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only root page's order
|
||||
*
|
||||
* @returns {Promise<PageOrder[]>}
|
||||
*/
|
||||
public static async getRootPageOrder(): Promise<PageOrder> {
|
||||
return PageOrder.getRootPageOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only child page's order
|
||||
*
|
||||
* @returns {Promise<PageOrder[]>}
|
||||
*/
|
||||
public static async getChildPageOrder(): Promise<PageOrder[]> {
|
||||
return PageOrder.getChildPageOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the child page to the parent's order list
|
||||
*
|
||||
|
|
|
@ -75,6 +75,28 @@ class PageOrder {
|
|||
return Promise.all(docs.map(doc => new PageOrder(doc)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only root page's order
|
||||
*
|
||||
* @returns {Promise<PageOrder[]>}
|
||||
*/
|
||||
public static async getRootPageOrder(): Promise<PageOrder> {
|
||||
const docs = await this.getAll();
|
||||
|
||||
return docs.filter(doc => doc.page === '0')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only child page's order
|
||||
*
|
||||
* @returns {Promise<PageOrder[]>}
|
||||
*/
|
||||
public static async getChildPageOrder(): Promise<PageOrder[]> {
|
||||
const docs = await this.getAll();
|
||||
|
||||
return docs.filter(doc => doc.page !== '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor data setter
|
||||
*
|
||||
|
|
|
@ -11,9 +11,7 @@ const router = express.Router();
|
|||
*/
|
||||
router.get('/page/new', verifyToken, allowEdit, async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const pagesAvailable = await Pages.getAll();
|
||||
const pagesAvailableSorted = Pages.sortByTimeDesc(pagesAvailable);
|
||||
const pagesAvailableGrouped = Pages.groupByParent(pagesAvailableSorted);
|
||||
const pagesAvailableGrouped = await Pages.groupByParent();
|
||||
|
||||
res.render('pages/form', {
|
||||
pagesAvailableGrouped,
|
||||
|
@ -34,6 +32,7 @@ router.get('/page/edit/:id', verifyToken, allowEdit, async (req: Request, res: R
|
|||
try {
|
||||
const page = await Pages.get(pageId);
|
||||
const pagesAvailable = await Pages.getAllExceptChildren(pageId);
|
||||
const pagesAvailableGrouped = await Pages.groupByParent(pageId);
|
||||
|
||||
if (!page._parent) {
|
||||
throw new Error('Parent not found');
|
||||
|
@ -44,7 +43,7 @@ router.get('/page/edit/:id', verifyToken, allowEdit, async (req: Request, res: R
|
|||
res.render('pages/form', {
|
||||
page,
|
||||
parentsChildrenOrdered,
|
||||
pagesAvailable,
|
||||
pagesAvailableGrouped,
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(404);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{% endif %}
|
||||
<select name="parent">
|
||||
<option value="0">Root</option>
|
||||
{% for _page in groupedPagesAvailable %}
|
||||
{% for _page in pagesAvailableGrouped %}
|
||||
{% if _page._id != currentPageId %}
|
||||
<option value="{{ _page._id }}" {{ page is not empty and page._parent == _page._id ? 'selected' : ''}}>
|
||||
{% if _page._parent != "0" %}
|
||||
|
|
|
@ -146,4 +146,31 @@ describe('PageOrder model', () => {
|
|||
|
||||
await pageOrder.destroy();
|
||||
});
|
||||
|
||||
it('Testing get parents and children order methods', async () => {
|
||||
const parentTestData = {
|
||||
page: '0',
|
||||
order: ['1', '2', '3', '4', '5'],
|
||||
};
|
||||
const childTestData = {
|
||||
page: 'child',
|
||||
order: ['a', 'b', 'c', 'd', 'e'],
|
||||
};
|
||||
|
||||
const parentOrder = new PageOrder(parentTestData);
|
||||
const childOrder = new PageOrder(childTestData);
|
||||
const insertedParentOrder = await parentOrder.save();
|
||||
const insertedChildOrder = await childOrder.save();
|
||||
const fetchedParentOrder = await PageOrder.getRootPageOrder();
|
||||
const fetchedChildOrder = await PageOrder.getChildPageOrder();
|
||||
|
||||
expect(fetchedParentOrder.page).to.deep.equals(parentTestData.page);
|
||||
expect(fetchedParentOrder.order).to.deep.equal(parentTestData.order);
|
||||
expect(fetchedChildOrder).to.be.an('array').that.is.length(1);
|
||||
expect(fetchedChildOrder[0].page).to.deep.equals(childTestData.page);
|
||||
expect(fetchedChildOrder[0].order).to.deep.equals(childTestData.order);
|
||||
|
||||
await insertedParentOrder.destroy();
|
||||
await insertedChildOrder.destroy();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue