Antraege durchsuchbar, Fortschritt sichtbar, Spieler an einem Stueck
Der Abgleich zeigt jetzt, was er tut. Gelesen wird zuerst von jedem Board die erste Seite - danach steht der Umfang fest, und der Balken zeigt einen ehrlichen Anteil statt einer Schaetzung. Ein Protokoll schreibt Seite fuer Seite mit. Beide Antragslisten lassen sich durchsuchen und wahlweise mit dem neuesten oder dem aeltesten Antrag zuerst anzeigen. Die Liste ohne zugeordneten Spieler blaettert seitenweise, statt bei fuenfhundert Eintraegen die ersten fuenfzig zu zeigen und den Rest zu verschweigen. Neu darueber: "Ersteller ohne Spieler" - dieselben Antraege, nach Ersteller zusammengefasst. Wer dreiundzwanzig Antraege gestellt hat, faellt dort auf, waehrend er zwischen fuenfhundert Einzelantraegen untergeht. Ein Klick legt den Spieler mit bereits eingetragenem Forum-Namen an. Ein Spieler laesst sich jetzt an einem Stueck abarbeiten, statt zwischen drei Seiten zu wechseln: - Seine Forums-Antraege stehen auf der Spielerseite, aeltester zuerst, jeder als Link ins Forum. Offene sind dort direkt entscheidbar, ueber denselben Weg wie auf der Antraege-Seite - danach stehen sie dort nicht mehr offen. - Pakete, die noch in einer Import-Vorschau liegen, erscheinen unter "Offene Pakete aus dem Abgleich" und lassen sich einzeln oder am Stueck buchen. Gebuchtes wird ueberall abgehakt, wo dieselbe Bestellung noch offen liegt, auch in einem zweiten Import - doppelt buchen ist ausgeschlossen. Wer ein Paket gar nicht buchen will, legt es weg, ohne das Konto zu beruehren. Die beiden Antrags-Dialoge liegen dafuer jetzt unter components/, weil beide Seiten sie brauchen.
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
listBoardChangeNotices,
|
||||
listThreads,
|
||||
listUnassignedThreads,
|
||||
listUntrackedAuthors,
|
||||
startScan,
|
||||
} from '../services/forum.js';
|
||||
import { contextOf, idParam, parseWith } from './helpers.js';
|
||||
@@ -31,6 +32,8 @@ export async function forumRoutes(app: FastifyInstance): Promise<void> {
|
||||
open: z.enum(['true', 'false']).default('true'),
|
||||
playerId: z.coerce.number().int().positive().optional(),
|
||||
board: z.nativeEnum(ForumBoard).optional(),
|
||||
q: z.string().trim().max(120).optional(),
|
||||
order: z.enum(['newest', 'oldest']).default('newest'),
|
||||
}),
|
||||
request.query,
|
||||
);
|
||||
@@ -38,8 +41,10 @@ export async function forumRoutes(app: FastifyInstance): Promise<void> {
|
||||
return {
|
||||
items: await listThreads({
|
||||
onlyOpen: query.open === 'true',
|
||||
order: query.order,
|
||||
...(query.playerId !== undefined ? { playerId: query.playerId } : {}),
|
||||
...(query.board ? { board: query.board } : {}),
|
||||
...(query.q ? { query: query.q } : {}),
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -49,16 +54,29 @@ export async function forumRoutes(app: FastifyInstance): Promise<void> {
|
||||
z.object({
|
||||
q: z.string().trim().max(120).optional(),
|
||||
take: z.coerce.number().int().min(1).max(200).default(50),
|
||||
skip: z.coerce.number().int().min(0).default(0),
|
||||
order: z.enum(['newest', 'oldest']).default('newest'),
|
||||
}),
|
||||
request.query,
|
||||
);
|
||||
|
||||
return listUnassignedThreads({
|
||||
take: query.take,
|
||||
skip: query.skip,
|
||||
order: query.order,
|
||||
...(query.q ? { query: query.q } : {}),
|
||||
});
|
||||
});
|
||||
|
||||
/** Ersteller aus dem Forum, die hier unter keinem Namen geführt werden. */
|
||||
app.get('/api/forum/authors/untracked', { preHandler: requireAuth }, async (request) => {
|
||||
const query = parseWith(
|
||||
z.object({ take: z.coerce.number().int().min(1).max(500).default(100) }),
|
||||
request.query,
|
||||
);
|
||||
return listUntrackedAuthors(query.take);
|
||||
});
|
||||
|
||||
app.get('/api/forum/notices', { preHandler: requireAuth }, async () => {
|
||||
return { items: await listBoardChangeNotices() };
|
||||
});
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
getImport,
|
||||
listImports,
|
||||
parseUpload,
|
||||
bookRows,
|
||||
dismissRows,
|
||||
} from '../services/imports.js';
|
||||
import { contextOf, idParam, parseWith } from './helpers.js';
|
||||
|
||||
@@ -63,6 +65,28 @@ export async function importRoutes(app: FastifyInstance): Promise<void> {
|
||||
return commitImport(id, contextOf(request));
|
||||
});
|
||||
|
||||
/**
|
||||
* Einzelne Zeilen sofort buchen, statt auf den ganzen Import zu warten.
|
||||
* Gedacht für den Weg über die Spielerseite: einen Spieler an einem Stück
|
||||
* abarbeiten. Gebuchtes verschwindet danach aus der Vorschau.
|
||||
*/
|
||||
app.post('/api/imports/rows/book', { preHandler: requireEditor }, async (request) => {
|
||||
const body = parseWith(
|
||||
z.object({ rowIds: z.array(z.number().int().positive()).min(1).max(500) }),
|
||||
request.body,
|
||||
);
|
||||
return bookRows(body.rowIds, contextOf(request));
|
||||
});
|
||||
|
||||
/** Zeilen aus der Vorschau nehmen, ohne sie zu buchen. */
|
||||
app.post('/api/imports/rows/dismiss', { preHandler: requireEditor }, async (request) => {
|
||||
const body = parseWith(
|
||||
z.object({ rowIds: z.array(z.number().int().positive()).min(1).max(500) }),
|
||||
request.body,
|
||||
);
|
||||
return dismissRows(body.rowIds, contextOf(request));
|
||||
});
|
||||
|
||||
app.post('/api/imports/:id/discard', { preHandler: requireEditor }, async (request) => {
|
||||
const { id } = parseWith(idParam, request.params);
|
||||
await discardImport(id, contextOf(request));
|
||||
|
||||
Reference in New Issue
Block a user