chore: add prettier with config and format all files
This commit is contained in:
@@ -5,7 +5,8 @@ import { withAuth } from '@/lib/apiHelpers';
|
||||
export const PUT = withAuth(async (req: NextRequest, { params }) => {
|
||||
const { id } = await params;
|
||||
const body = await req.json();
|
||||
const { item_key, item_key_is_regex, combinator, signal_type, condition, threshold, active } = body;
|
||||
const { item_key, item_key_is_regex, combinator, signal_type, condition, threshold, active } =
|
||||
body;
|
||||
|
||||
const result = await pool.query(
|
||||
`UPDATE alerts SET
|
||||
@@ -29,4 +30,4 @@ export const DELETE = withAuth(async (_req: NextRequest, { params }) => {
|
||||
const result = await pool.query('DELETE FROM alerts WHERE id = $1', [id]);
|
||||
if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
||||
return NextResponse.json({ ok: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,10 @@ export const GET = withAuth(async () => {
|
||||
if (alertsResult.rows.length === 0) return NextResponse.json([]);
|
||||
|
||||
const latestResult = await pool.query<{
|
||||
combinator: string; item_key: string; green: number; red: number;
|
||||
combinator: string;
|
||||
item_key: string;
|
||||
green: number;
|
||||
red: number;
|
||||
}>(
|
||||
`SELECT DISTINCT ON (combinator, item_key) combinator, item_key, green, red
|
||||
FROM signals
|
||||
@@ -22,9 +25,7 @@ export const GET = withAuth(async () => {
|
||||
|
||||
const localeMap = getServerLocaleMap();
|
||||
|
||||
const latestMap = new Map(
|
||||
latestResult.rows.map(r => [`${r.combinator}::${r.item_key}`, r]),
|
||||
);
|
||||
const latestMap = new Map(latestResult.rows.map((r) => [`${r.combinator}::${r.item_key}`, r]));
|
||||
|
||||
const triggered: TriggeredAlert[] = [];
|
||||
|
||||
@@ -49,14 +50,15 @@ export const GET = withAuth(async () => {
|
||||
|
||||
const value = alert.signal_type === 'green' ? vals.green : vals.red;
|
||||
const fired = alert.condition === 'above' ? value > alert.threshold : value < alert.threshold;
|
||||
if (fired) triggered.push({
|
||||
...alert,
|
||||
current_value: value,
|
||||
combinator_match: combinator,
|
||||
matched_item_key: item_key,
|
||||
});
|
||||
if (fired)
|
||||
triggered.push({
|
||||
...alert,
|
||||
current_value: value,
|
||||
combinator_match: combinator,
|
||||
matched_item_key: item_key,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(triggered);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,15 +10,16 @@ export const GET = withAuth(async () => {
|
||||
export const POST = withAuth(async (req: NextRequest) => {
|
||||
const body = await req.json();
|
||||
const {
|
||||
item_key, item_key_is_regex = false,
|
||||
combinator = null, signal_type = 'green', condition, threshold,
|
||||
item_key,
|
||||
item_key_is_regex = false,
|
||||
combinator = null,
|
||||
signal_type = 'green',
|
||||
condition,
|
||||
threshold,
|
||||
} = body;
|
||||
|
||||
if (!item_key || !condition || threshold === undefined) {
|
||||
return NextResponse.json(
|
||||
{ error: 'item_key, condition, threshold required' },
|
||||
{ status: 400 },
|
||||
);
|
||||
return NextResponse.json({ error: 'item_key, condition, threshold required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
@@ -27,4 +28,4 @@ export const POST = withAuth(async (req: NextRequest) => {
|
||||
[item_key, item_key_is_regex, combinator, signal_type, condition, threshold],
|
||||
);
|
||||
return NextResponse.json(result.rows[0], { status: 201 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,17 +6,25 @@ export const PUT = withAuth(async (req: NextRequest, { params }) => {
|
||||
const { id } = await params;
|
||||
const body = await req.json();
|
||||
const {
|
||||
title, pos_x, pos_y, width, height,
|
||||
signal_type, chart_type, viz_type,
|
||||
filter_items_regex, y_scale,
|
||||
series_limit, order_by,
|
||||
title,
|
||||
pos_x,
|
||||
pos_y,
|
||||
width,
|
||||
height,
|
||||
signal_type,
|
||||
chart_type,
|
||||
viz_type,
|
||||
filter_items_regex,
|
||||
y_scale,
|
||||
series_limit,
|
||||
order_by,
|
||||
} = body;
|
||||
|
||||
const hasFilterCombinators = 'filter_combinators' in body;
|
||||
const hasFilterItems = 'filter_items' in body;
|
||||
const hasFilterCombinators = 'filter_combinators' in body;
|
||||
const hasFilterItems = 'filter_items' in body;
|
||||
const hasFilterItemsExclude = 'filter_items_exclude' in body;
|
||||
const hasYMin = 'y_min' in body;
|
||||
const hasYMax = 'y_max' in body;
|
||||
const hasYMin = 'y_min' in body;
|
||||
const hasYMax = 'y_max' in body;
|
||||
|
||||
const result = await pool.query(
|
||||
`UPDATE charts SET
|
||||
@@ -40,15 +48,28 @@ export const PUT = withAuth(async (req: NextRequest, { params }) => {
|
||||
WHERE id = $23
|
||||
RETURNING *`,
|
||||
[
|
||||
title, pos_x, pos_y, width, height, signal_type, chart_type, viz_type,
|
||||
hasFilterCombinators, body.filter_combinators ?? null,
|
||||
hasFilterItems, body.filter_items ?? null,
|
||||
hasFilterItemsExclude, body.filter_items_exclude ?? null,
|
||||
title,
|
||||
pos_x,
|
||||
pos_y,
|
||||
width,
|
||||
height,
|
||||
signal_type,
|
||||
chart_type,
|
||||
viz_type,
|
||||
hasFilterCombinators,
|
||||
body.filter_combinators ?? null,
|
||||
hasFilterItems,
|
||||
body.filter_items ?? null,
|
||||
hasFilterItemsExclude,
|
||||
body.filter_items_exclude ?? null,
|
||||
filter_items_regex,
|
||||
hasYMin, body.y_min ?? null,
|
||||
hasYMax, body.y_max ?? null,
|
||||
hasYMin,
|
||||
body.y_min ?? null,
|
||||
hasYMax,
|
||||
body.y_max ?? null,
|
||||
y_scale,
|
||||
series_limit, order_by,
|
||||
series_limit,
|
||||
order_by,
|
||||
id,
|
||||
],
|
||||
);
|
||||
@@ -61,4 +82,4 @@ export const DELETE = withAuth(async (_req: NextRequest, { params }) => {
|
||||
const result = await pool.query('DELETE FROM charts WHERE id = $1', [id]);
|
||||
if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
||||
return NextResponse.json({ ok: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,12 +11,22 @@ export const POST = withAuth(async (req: NextRequest) => {
|
||||
const body = await req.json();
|
||||
const {
|
||||
title,
|
||||
pos_x = 0, pos_y = 0, width = 2, height = 4,
|
||||
signal_type = 'both', chart_type = 'signals', viz_type = 'line',
|
||||
filter_combinators = null, filter_items = null,
|
||||
filter_items_exclude = null, filter_items_regex = false,
|
||||
y_min = null, y_max = null, y_scale = 'linear',
|
||||
series_limit = 20, order_by = 'value_asc',
|
||||
pos_x = 0,
|
||||
pos_y = 0,
|
||||
width = 2,
|
||||
height = 4,
|
||||
signal_type = 'both',
|
||||
chart_type = 'signals',
|
||||
viz_type = 'line',
|
||||
filter_combinators = null,
|
||||
filter_items = null,
|
||||
filter_items_exclude = null,
|
||||
filter_items_regex = false,
|
||||
y_min = null,
|
||||
y_max = null,
|
||||
y_scale = 'linear',
|
||||
series_limit = 20,
|
||||
order_by = 'value_asc',
|
||||
} = body;
|
||||
|
||||
if (!title) return NextResponse.json({ error: 'title required' }, { status: 400 });
|
||||
@@ -28,9 +38,25 @@ export const POST = withAuth(async (req: NextRequest) => {
|
||||
y_min,y_max,y_scale,series_limit,order_by)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)
|
||||
RETURNING *`,
|
||||
[title,pos_x,pos_y,width,height,signal_type,chart_type,viz_type,
|
||||
filter_combinators,filter_items,filter_items_exclude,filter_items_regex,
|
||||
y_min,y_max,y_scale,series_limit,order_by],
|
||||
[
|
||||
title,
|
||||
pos_x,
|
||||
pos_y,
|
||||
width,
|
||||
height,
|
||||
signal_type,
|
||||
chart_type,
|
||||
viz_type,
|
||||
filter_combinators,
|
||||
filter_items,
|
||||
filter_items_exclude,
|
||||
filter_items_regex,
|
||||
y_min,
|
||||
y_max,
|
||||
y_scale,
|
||||
series_limit,
|
||||
order_by,
|
||||
],
|
||||
);
|
||||
return NextResponse.json(result.rows[0], { status: 201 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ import { withAuth } from '@/lib/apiHelpers';
|
||||
|
||||
interface CircuitNetwork {
|
||||
green: Record<string, number>;
|
||||
red: Record<string, number>;
|
||||
red: Record<string, number>;
|
||||
}
|
||||
|
||||
interface IngestBody {
|
||||
game_tick: number;
|
||||
game_tick: number;
|
||||
circuit_network: CircuitNetwork;
|
||||
logistic_network: Record<string, number>;
|
||||
}
|
||||
@@ -31,10 +31,10 @@ export const POST = withAuth(async (req: NextRequest, { params }) => {
|
||||
return NextResponse.json({ error: 'Missing game_tick' }, { status: 400 });
|
||||
}
|
||||
|
||||
const green = circuit_network?.green ?? {};
|
||||
const red = circuit_network?.red ?? {};
|
||||
const logistic = logistic_network ?? {};
|
||||
const allKeys = new Set([...Object.keys(green), ...Object.keys(red), ...Object.keys(logistic)]);
|
||||
const green = circuit_network?.green ?? {};
|
||||
const red = circuit_network?.red ?? {};
|
||||
const logistic = logistic_network ?? {};
|
||||
const allKeys = new Set([...Object.keys(green), ...Object.keys(red), ...Object.keys(logistic)]);
|
||||
|
||||
if (allKeys.size === 0) return NextResponse.json({ ok: true, rows: 0 });
|
||||
|
||||
@@ -47,7 +47,15 @@ export const POST = withAuth(async (req: NextRequest, { params }) => {
|
||||
let idx = 1;
|
||||
for (const key of allKeys) {
|
||||
placeholders.push(`($${idx++},$${idx++},$${idx++},$${idx++},$${idx++},$${idx++},$${idx++})`);
|
||||
values.push(realTime, game_tick, combinator, key, green[key] ?? 0, red[key] ?? 0, logistic[key] ?? null);
|
||||
values.push(
|
||||
realTime,
|
||||
game_tick,
|
||||
combinator,
|
||||
key,
|
||||
green[key] ?? 0,
|
||||
red[key] ?? 0,
|
||||
logistic[key] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
await client.query(
|
||||
@@ -68,4 +76,4 @@ export const POST = withAuth(async (req: NextRequest, { params }) => {
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { withAuth } from '@/lib/apiHelpers';
|
||||
export const GET = withAuth(async (req: NextRequest) => {
|
||||
const p = req.nextUrl.searchParams;
|
||||
const from = p.get('from') ? new Date(p.get('from')!) : new Date(Date.now() - 86_400_000);
|
||||
const to = p.get('to') ? new Date(p.get('to')!) : new Date();
|
||||
const to = p.get('to') ? new Date(p.get('to')!) : new Date();
|
||||
const boundaries = await getSessionBoundaries(from, to);
|
||||
return NextResponse.json(boundaries);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,15 +6,15 @@ import { matchKeys } from '@/lib/localization';
|
||||
|
||||
export const GET = withAuth(async (req: NextRequest) => {
|
||||
const p = req.nextUrl.searchParams;
|
||||
const combinators = p.getAll('combinator');
|
||||
const combinators = p.getAll('combinator');
|
||||
const itemsWhitelist = p.getAll('item');
|
||||
const itemsBlacklist = p.getAll('exclude');
|
||||
const signalType = p.get('signal') ?? 'both';
|
||||
const from = p.get('from');
|
||||
const to = p.get('to');
|
||||
const useRegex = p.get('regex') === 'true';
|
||||
const orderBy = p.get('order_by') ?? 'value_asc';
|
||||
const limit = p.get('limit') ? parseInt(p.get('limit')!, 10) : null;
|
||||
const signalType = p.get('signal') ?? 'both';
|
||||
const from = p.get('from');
|
||||
const to = p.get('to');
|
||||
const useRegex = p.get('regex') === 'true';
|
||||
const orderBy = p.get('order_by') ?? 'value_asc';
|
||||
const limit = p.get('limit') ? parseInt(p.get('limit')!, 10) : null;
|
||||
|
||||
const conditions: string[] = [];
|
||||
const values: unknown[] = [];
|
||||
@@ -28,8 +28,8 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
if (itemsWhitelist.length > 0) {
|
||||
if (useRegex) {
|
||||
const localeMap = getServerLocaleMap();
|
||||
const localeKeys = [...new Set(itemsWhitelist.flatMap(p => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsWhitelist.map(p => `(${p})`).join('|');
|
||||
const localeKeys = [...new Set(itemsWhitelist.flatMap((p) => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsWhitelist.map((p) => `(${p})`).join('|');
|
||||
const orConds = [`item_key ~* $${i++}`];
|
||||
values.push(sqlPattern);
|
||||
if (localeKeys.length > 0) {
|
||||
@@ -46,8 +46,8 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
if (itemsBlacklist.length > 0) {
|
||||
if (useRegex) {
|
||||
const localeMap = getServerLocaleMap();
|
||||
const localeKeys = [...new Set(itemsBlacklist.flatMap(p => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsBlacklist.map(p => `(${p})`).join('|');
|
||||
const localeKeys = [...new Set(itemsBlacklist.flatMap((p) => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsBlacklist.map((p) => `(${p})`).join('|');
|
||||
const andConds = [`item_key !~* $${i++}`];
|
||||
values.push(sqlPattern);
|
||||
if (localeKeys.length > 0) {
|
||||
@@ -61,16 +61,24 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (from) { conditions.push(`real_time >= $${i++}`); values.push(new Date(from)); }
|
||||
if (to) { conditions.push(`real_time <= $${i++}`); values.push(new Date(to)); }
|
||||
if (from) {
|
||||
conditions.push(`real_time >= $${i++}`);
|
||||
values.push(new Date(from));
|
||||
}
|
||||
if (to) {
|
||||
conditions.push(`real_time <= $${i++}`);
|
||||
values.push(new Date(to));
|
||||
}
|
||||
|
||||
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
||||
|
||||
const valueCol = signalType === 'red' ? 'red' : 'green';
|
||||
const valueCol = signalType === 'red' ? 'red' : 'green';
|
||||
const selectCols =
|
||||
signalType === 'green' ? 'real_time, game_tick, combinator, item_key, green'
|
||||
: signalType === 'red' ? 'real_time, game_tick, combinator, item_key, red'
|
||||
: 'real_time, game_tick, combinator, item_key, green, red';
|
||||
signalType === 'green'
|
||||
? 'real_time, game_tick, combinator, item_key, green'
|
||||
: signalType === 'red'
|
||||
? 'real_time, game_tick, combinator, item_key, red'
|
||||
: 'real_time, game_tick, combinator, item_key, green, red';
|
||||
|
||||
if ((orderBy === 'delta_asc' || orderBy === 'delta_desc') && limit !== null) {
|
||||
const baseConditions: string[] = [];
|
||||
@@ -84,8 +92,8 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
if (itemsWhitelist.length > 0) {
|
||||
if (useRegex) {
|
||||
const localeMap = getServerLocaleMap();
|
||||
const localeKeys = [...new Set(itemsWhitelist.flatMap(p => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsWhitelist.map(p => `(${p})`).join('|');
|
||||
const localeKeys = [...new Set(itemsWhitelist.flatMap((p) => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsWhitelist.map((p) => `(${p})`).join('|');
|
||||
const orConds = [`item_key ~* $${j++}`];
|
||||
baseValues.push(sqlPattern);
|
||||
if (localeKeys.length > 0) {
|
||||
@@ -101,8 +109,8 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
if (itemsBlacklist.length > 0) {
|
||||
if (useRegex) {
|
||||
const localeMap = getServerLocaleMap();
|
||||
const localeKeys = [...new Set(itemsBlacklist.flatMap(p => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsBlacklist.map(p => `(${p})`).join('|');
|
||||
const localeKeys = [...new Set(itemsBlacklist.flatMap((p) => matchKeys(p, localeMap)))];
|
||||
const sqlPattern = itemsBlacklist.map((p) => `(${p})`).join('|');
|
||||
const andConds = [`item_key !~* $${j++}`];
|
||||
baseValues.push(sqlPattern);
|
||||
if (localeKeys.length > 0) {
|
||||
@@ -116,7 +124,7 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
}
|
||||
}
|
||||
|
||||
const baseWhere = baseConditions.length > 0 ? `WHERE ${baseConditions.join(' AND ')}` : '';
|
||||
const baseWhere = baseConditions.length > 0 ? `WHERE ${baseConditions.join(' AND ')}` : '';
|
||||
const baseWhereAnd = baseConditions.length > 0 ? `AND ${baseConditions.join(' AND ')}` : '';
|
||||
|
||||
const deltaQuery = `
|
||||
@@ -158,21 +166,27 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
const top = deltaResult.rows;
|
||||
if (top.length === 0) return NextResponse.json([]);
|
||||
|
||||
const seriesConditions = top.map((_, idx) =>
|
||||
`(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`,
|
||||
const seriesConditions = top.map(
|
||||
(_, idx) => `(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`,
|
||||
);
|
||||
const fullWhere = `${where ? where + ' AND' : 'WHERE'} (${seriesConditions.join(' OR ')})`;
|
||||
const orderCase = top.map((_, idx) =>
|
||||
`WHEN combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1} THEN ${idx}`,
|
||||
).join(' ');
|
||||
const orderCase = top
|
||||
.map(
|
||||
(_, idx) =>
|
||||
`WHEN combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1} THEN ${idx}`,
|
||||
)
|
||||
.join(' ');
|
||||
const result = await pool.query(
|
||||
`SELECT ${selectCols} FROM signals ${fullWhere} ORDER BY CASE ${orderCase} ELSE ${top.length} END, real_time ASC`,
|
||||
[...values, ...top.flatMap(r => [r.combinator, r.item_key])],
|
||||
[...values, ...top.flatMap((r) => [r.combinator, r.item_key])],
|
||||
);
|
||||
return NextResponse.json(result.rows);
|
||||
}
|
||||
|
||||
if ((orderBy === 'value_asc' || orderBy === 'value_desc' || orderBy === 'abs_desc') && limit !== null) {
|
||||
if (
|
||||
(orderBy === 'value_asc' || orderBy === 'value_desc' || orderBy === 'abs_desc') &&
|
||||
limit !== null
|
||||
) {
|
||||
const latestVals = await pool.query<{ combinator: string; item_key: string; val: number }>(
|
||||
`SELECT DISTINCT ON (combinator, item_key)
|
||||
combinator, item_key, ${valueCol} AS val
|
||||
@@ -182,23 +196,27 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
);
|
||||
|
||||
let sorted = latestVals.rows;
|
||||
if (orderBy === 'value_asc') sorted = [...sorted].sort((a, b) => a.val - b.val);
|
||||
if (orderBy === 'value_asc') sorted = [...sorted].sort((a, b) => a.val - b.val);
|
||||
if (orderBy === 'value_desc') sorted = [...sorted].sort((a, b) => b.val - a.val);
|
||||
if (orderBy === 'abs_desc') sorted = [...sorted].sort((a, b) => Math.abs(b.val) - Math.abs(a.val));
|
||||
if (orderBy === 'abs_desc')
|
||||
sorted = [...sorted].sort((a, b) => Math.abs(b.val) - Math.abs(a.val));
|
||||
|
||||
const top = sorted.slice(0, limit);
|
||||
if (top.length === 0) return NextResponse.json([]);
|
||||
|
||||
const seriesConditions = top.map((_, idx) =>
|
||||
`(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`,
|
||||
const seriesConditions = top.map(
|
||||
(_, idx) => `(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`,
|
||||
);
|
||||
const fullWhere = `${where ? where + ' AND' : 'WHERE'} (${seriesConditions.join(' OR ')})`;
|
||||
const orderCase = top.map((_, idx) =>
|
||||
`WHEN combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1} THEN ${idx}`,
|
||||
).join(' ');
|
||||
const orderCase = top
|
||||
.map(
|
||||
(_, idx) =>
|
||||
`WHEN combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1} THEN ${idx}`,
|
||||
)
|
||||
.join(' ');
|
||||
const result = await pool.query(
|
||||
`SELECT ${selectCols} FROM signals ${fullWhere} ORDER BY CASE ${orderCase} ELSE ${top.length} END, real_time ASC`,
|
||||
[...values, ...top.flatMap(r => [r.combinator, r.item_key])],
|
||||
[...values, ...top.flatMap((r) => [r.combinator, r.item_key])],
|
||||
);
|
||||
return NextResponse.json(result.rows);
|
||||
}
|
||||
@@ -209,4 +227,4 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
values,
|
||||
);
|
||||
return NextResponse.json(result.rows);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
const p = req.nextUrl.searchParams;
|
||||
const combinator = p.get('combinator');
|
||||
const from = p.get('from') ? new Date(p.get('from')!) : new Date(Date.now() - 86_400_000);
|
||||
const to = p.get('to') ? new Date(p.get('to')!) : new Date();
|
||||
const to = p.get('to') ? new Date(p.get('to')!) : new Date();
|
||||
|
||||
const conditions = ['real_time BETWEEN $1 AND $2'];
|
||||
const values: unknown[] = [from, to];
|
||||
@@ -17,7 +17,9 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
}
|
||||
|
||||
const result = await pool.query<{
|
||||
real_time: Date; game_tick: string; combinator: string;
|
||||
real_time: Date;
|
||||
game_tick: string;
|
||||
combinator: string;
|
||||
}>(
|
||||
`SELECT real_time, game_tick, combinator
|
||||
FROM tick_timing
|
||||
@@ -43,17 +45,17 @@ export const GET = withAuth(async (req: NextRequest) => {
|
||||
const prev = combiRows[i - 1];
|
||||
const curr = combiRows[i];
|
||||
const deltaRealMs = curr.real_time.getTime() - prev.real_time.getTime();
|
||||
const deltaTicks = parseInt(curr.game_tick, 10) - parseInt(prev.game_tick, 10);
|
||||
const deltaTicks = parseInt(curr.game_tick, 10) - parseInt(prev.game_tick, 10);
|
||||
// Skip session gaps and bad data
|
||||
if (deltaRealMs > 30 * 60 * 1000 || deltaRealMs <= 0 || deltaTicks <= 0) continue;
|
||||
points.push({
|
||||
real_time: curr.real_time.toISOString(),
|
||||
game_tick: parseInt(curr.game_tick, 10),
|
||||
real_time: curr.real_time.toISOString(),
|
||||
game_tick: parseInt(curr.game_tick, 10),
|
||||
combinator: combi,
|
||||
ups: Math.round((deltaTicks / deltaRealMs) * 1000 * 10) / 10,
|
||||
ups: Math.round((deltaTicks / deltaRealMs) * 1000 * 10) / 10,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(points);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "tailwindcss";
|
||||
@import 'tailwindcss';
|
||||
|
||||
:root {
|
||||
--background: #111827;
|
||||
@@ -15,4 +15,3 @@ body {
|
||||
color: var(--foreground);
|
||||
font-family: ui-sans-serif, system-ui, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import type { Metadata } from 'next';
|
||||
import './globals.css';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Factorio Dashboard",
|
||||
description: "Factorio signal monitor",
|
||||
title: 'Factorio Dashboard',
|
||||
description: 'Factorio signal monitor',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) {
|
||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
return (
|
||||
<html lang="en" className="h-full antialiased">
|
||||
<body className="min-h-full flex flex-col">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ function DashboardApp() {
|
||||
const searchParams = useSearchParams();
|
||||
const token = searchParams.get('token') ?? '';
|
||||
|
||||
const [ready, setReady] = useState(false);
|
||||
const [alerts, setAlerts] = useState<AlertConfig[]>([]);
|
||||
const [ready, setReady] = useState(false);
|
||||
const [alerts, setAlerts] = useState<AlertConfig[]>([]);
|
||||
const [localeMap, setLocaleMap] = useState<LocaleMap>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
@@ -72,9 +72,7 @@ function DashboardApp() {
|
||||
|
||||
if (!ready) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center text-gray-400">
|
||||
Loading…
|
||||
</div>
|
||||
<div className="flex min-h-screen items-center justify-center text-gray-400">Loading…</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,4 +89,4 @@ export default function Page() {
|
||||
<DashboardApp />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user