1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

Server: Improved log table too and made it sortable

This commit is contained in:
Laurent Cozic 2021-05-17 17:29:21 +02:00
parent 7f05420fda
commit ec7f0f479a
5 changed files with 62 additions and 102 deletions

View File

@ -1,4 +1,4 @@
import { beforeAllDb, afterAllTests, beforeEachDb, createItemTree, createUserAndSession } from '../../utils/testing/testUtils';
import { beforeAllDb, afterAllTests, beforeEachDb, createItemTree, createUserAndSession, parseHtml } from '../../utils/testing/testUtils';
import { execRequest } from '../../utils/testing/apiUtils';
describe('index_changes', function() {
@ -30,14 +30,22 @@ describe('index_changes', function() {
{
const response: string = await execRequest(session1.id, 'GET', 'changes');
const navLinks = parseHtml(response).querySelectorAll('.pagination-link');
expect(response.includes('00000000000000000000000000000150.md')).toBe(true);
expect(response.includes('00000000000000000000000000000051.md')).toBe(true);
expect(navLinks.length).toBe(2);
expect(navLinks[0].getAttribute('class')).toContain('is-current');
expect(navLinks[1].getAttribute('class')).not.toContain('is-current');
}
{
const response: string = await execRequest(session1.id, 'GET', 'changes', null, { query: { page: 2 } });
const navLinks = parseHtml(response).querySelectorAll('.pagination-link');
expect(response.includes('00000000000000000000000000000050.md')).toBe(true);
expect(response.includes('00000000000000000000000000000001.md')).toBe(true);
expect(navLinks.length).toBe(2);
expect(navLinks[0].getAttribute('class')).not.toContain('is-current');
expect(navLinks[1].getAttribute('class')).toContain('is-current');
}
});

View File

@ -2,86 +2,62 @@ import { SubPath } from '../../utils/routeUtils';
import Router from '../../utils/Router';
import { AppContext } from '../../utils/types';
import { changeTypeToString } from '../../db';
import { createPaginationLinks, filterPaginationQueryParams, queryParamsToPagination } from '../../models/utils/pagination';
import { setQueryParameters } from '../../utils/urlUtils';
import { PaginationOrderDir } from '../../models/utils/pagination';
import { formatDateTime } from '../../utils/time';
import defaultView from '../../utils/defaultView';
import { View } from '../../services/MustacheService';
interface ItemToDisplay {
name: string;
changeType: string;
timestamp: string;
url: string;
}
import { makeTablePagination, Table, Row, makeTableView, tablePartials } from '../../utils/views/table';
const router = new Router();
router.get('changes', async (_path: SubPath, ctx: AppContext) => {
const changeModel = ctx.models.change();
const itemModel = ctx.models.item();
const pagination = queryParamsToPagination(ctx.query);
// {
// "items": [
// {
// "type": 3,
// "item": {
// "id": "QZbQVWTCtr9qpxtEsuWMoQbax8wR1Q75",
// "name": "sync_desktop_bbecbb2d6bf44a16aa14c14f6c51719d.json"
// }
// },
// {
// "type": 1,
// "item": {
// "id": "8ogKqMu58u1FcZ9gaBO1yqPHKzniZSfx",
// "owner_id": "Pg8NSIS3fo7sotSktqb2Rza7EJFcpj3M",
// "name": "ab9e895491844213a43338608deaf573.md",
// "mime_type": "text/markdown",
// "size": 908,
// "is_directory": 0,
// "is_root": 0,
// "parent_id": "5IhOFX314EZOL21p9UUVKZElgjhuUerV",
// "updated_time": 1616235197809,
// "created_time": 1616235197809
// }
// }
// ]
// }
const paginatedChanges = await changeModel.allByUser(ctx.owner.id, pagination);
const itemsToDisplay: ItemToDisplay[] = [];
const pagination = makeTablePagination(ctx.query, 'updated_time', PaginationOrderDir.DESC);
const paginatedChanges = await ctx.models.change().allByUser(ctx.owner.id, pagination);
const items = await ctx.models.item().loadByIds(paginatedChanges.items.map(i => i.item_id), { fields: ['id'] });
for (const item of paginatedChanges.items) {
itemsToDisplay.push({
name: item.item_name,
changeType: changeTypeToString(item.type),
timestamp: formatDateTime(item.updated_time),
const table: Table = {
baseUrl: ctx.models.change().changeUrl(),
requestQuery: ctx.query,
pageCount: paginatedChanges.page_count,
pagination,
headers: [
{
name: 'item_name',
label: 'Name',
stretch: true,
},
{
name: 'type',
label: 'Type',
},
{
name: 'updated_time',
label: 'Timestamp',
},
],
rows: paginatedChanges.items.map(change => {
const row: Row = [
{
value: change.item_name,
stretch: true,
url: items.find(i => i.id === change.item_id) ? ctx.models.item().itemContentUrl(change.item_id) : '',
},
{
value: changeTypeToString(change.type),
},
{
value: formatDateTime(change.updated_time),
},
];
// The item associated with the change may have been deleted, and we
// only display a link for existing items.
url: items.find(i => i.id === item.item_id) ? await itemModel.itemContentUrl(item.item_id) : '',
});
}
const paginationLinks = createPaginationLinks(
pagination.page,
paginatedChanges.page_count,
setQueryParameters(
changeModel.changeUrl(), {
...filterPaginationQueryParams(ctx.query),
'page': 'PAGE_NUMBER',
}
)
);
return row;
}),
};
const view: View = defaultView('changes');
view.content.paginatedChanges = { ...paginatedChanges, items: itemsToDisplay };
view.content.paginationLinks = paginationLinks;
view.content.changeTable = makeTableView(table),
view.cssFiles = ['index/changes'];
view.partials.push('pagination');
view.partials = view.partials.concat(tablePartials());
return view;
});

View File

@ -8,18 +8,19 @@ import { formatDateTime } from '../../utils/time';
import defaultView from '../../utils/defaultView';
import { View } from '../../services/MustacheService';
import { makeTablePagination, makeTableView, Row, Table, tablePartials } from '../../utils/views/table';
import { PaginationOrderDir } from '../../models/utils/pagination';
const prettyBytes = require('pretty-bytes');
const router = new Router();
router.get('items', async (_path: SubPath, ctx: AppContext) => {
const pagination = makeTablePagination(ctx.query);
const pagination = makeTablePagination(ctx.query, 'name', PaginationOrderDir.ASC);
const paginatedItems = await ctx.models.item().children(ctx.owner.id, '', pagination, { fields: ['id', 'name', 'updated_time', 'mime_type', 'content_size'] });
const table: Table = {
baseUrl: ctx.models.item().itemUrl(),
requestQuery: ctx.query,
totalItemCount: await ctx.models.item().childrenCount(ctx.owner.id, ''),
pageCount: Math.ceil((await ctx.models.item().childrenCount(ctx.owner.id, '')) / pagination.limit),
pagination,
headers: [
{

View File

@ -54,7 +54,7 @@ export interface Table {
rows: Row[];
baseUrl: string;
requestQuery: any;
totalItemCount: number;
pageCount: number;
pagination: Pagination;
}
@ -64,9 +64,9 @@ export interface TableView {
paginationLinks: PageLink[];
}
export function makeTablePagination(query: any): Pagination {
export function makeTablePagination(query: any, defaultOrderField: string, defaultOrderDir: PaginationOrderDir): Pagination {
const limit = Number(query.limit) || pageMaxSize;
const order: PaginationOrder[] = requestPaginationOrder(query, 'name', PaginationOrderDir.ASC);
const order: PaginationOrder[] = requestPaginationOrder(query, defaultOrderField, defaultOrderDir);
const page: number = 'page' in query ? Number(query.page) : 1;
const output: Pagination = { limit, order, page };
@ -96,8 +96,7 @@ function makeRowView(row: Row): RowView {
export function makeTableView(table: Table): TableView {
const baseUrlQuery = filterPaginationQueryParams(table.requestQuery);
const pagination = table.pagination;
const pageCount = Math.ceil(table.totalItemCount / pagination.limit);
const paginationLinks = createPaginationLinks(pagination.page, pageCount, setQueryParameters(table.baseUrl, { ...baseUrlQuery, 'page': 'PAGE_NUMBER' }));
const paginationLinks = createPaginationLinks(pagination.page, table.pageCount, setQueryParameters(table.baseUrl, { ...baseUrlQuery, 'page': 'PAGE_NUMBER' }));
return {
headers: table.headers.map(h => makeHeaderView(h, table.baseUrl, baseUrlQuery, pagination)),

View File

@ -1,27 +1,3 @@
<table class="table is-fullwidth is-hoverable">
<thead>
<tr>
<th class="stretch">Item</th>
<th class="nowrap">Change</th>
<th class="nowrap">Timestamp</th>
</tr>
</thead>
<tbody>
{{#paginatedChanges.items}}
<tr>
<td class="stretch item-{{type}}">
{{#url}}
<a href="{{url}}">{{name}}</a>
{{/url}}
{{^url}}
{{name}}
{{/url}}
</td>
<td class="nowrap">{{changeType}}</td>
<td class="nowrap">{{timestamp}}</td>
</tr>
{{/paginatedChanges.items}}
</tbody>
</table>
{{>pagination}}
{{#changeTable}}
{{>table}}
{{/changeTable}}