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:
parent
7f05420fda
commit
ec7f0f479a
@ -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');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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: [
|
||||
{
|
||||
|
@ -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)),
|
||||
|
@ -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}}
|
||||
|
Loading…
Reference in New Issue
Block a user