27 Commits

Author SHA1 Message Date
a2a1151ccb Merge pull request 'dev' (#241) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m5s
Build and Release FEDEO / build-and-release (push) Successful in 6m29s
Reviewed-on: #241
2026-10-07 17:11:45 +00:00
15e480ee9a fix(build): isolate time tests by Docker build context
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m0s
Build and Release FEDEO / build-and-release (push) Successful in 6m4s
2026-10-07 19:02:23 +02:00
daaed01d02 Merge pull request 'dev' (#240) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 59s
Build and Release FEDEO / build-and-release (push) Successful in 6m16s
Reviewed-on: #240
2026-10-02 16:30:02 +00:00
e7d6c482ad Merge pull request 'dev' (#239) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 58s
Build and Release FEDEO / build-and-release (push) Successful in 6m13s
Reviewed-on: #239
2026-10-02 15:17:16 +00:00
ed305f656c Merge pull request 'dev' (#238) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 57s
Build and Release FEDEO / build-and-release (push) Successful in 6m14s
Reviewed-on: #238
2026-10-02 14:18:01 +00:00
30e932a874 Merge pull request 'dev' (#237) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 58s
Build and Release FEDEO / build-and-release (push) Successful in 6m16s
Reviewed-on: #237
2026-10-02 12:51:46 +00:00
0a74e07288 Merge pull request 'fix(scanner): accept Epson empty write probes' (#234) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 58s
Build and Release FEDEO / build-and-release (push) Successful in 6m8s
Reviewed-on: #234
2026-10-01 15:36:56 +00:00
4c3de8c942 Merge pull request 'dev' (#233) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 58s
Build and Release FEDEO / build-and-release (push) Successful in 6m11s
Reviewed-on: #233
2026-09-30 17:23:15 +00:00
49d44d9701 Merge pull request 'dev' (#232) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m1s
Build and Release FEDEO / build-and-release (push) Successful in 6m18s
Reviewed-on: #232
2026-09-30 15:43:45 +00:00
96a7acff33 Merge pull request 'feat(selfhost): show sanitized update logs in admin UI' (#231) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 47s
Build and Release FEDEO / build-and-release (push) Successful in 6m7s
Reviewed-on: #231
2026-09-25 17:22:30 +00:00
65588686c7 Merge pull request 'fix(documents): normalize units when selecting and loading rows' (#230) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 48s
Build and Release FEDEO / build-and-release (push) Successful in 6m3s
Reviewed-on: #230
2026-09-25 09:54:08 +00:00
fcf9cc3fc9 Merge pull request 'dev' (#229) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 49s
Build and Release FEDEO / build-and-release (push) Successful in 6m6s
Reviewed-on: #229
2026-09-25 09:24:39 +00:00
20091143d2 Merge pull request 'dev' (#228) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 45s
Build and Release FEDEO / build-and-release (push) Successful in 6m5s
Reviewed-on: #228
2026-09-23 17:20:58 +00:00
f708d0a2b2 Merge pull request 'dev' (#227) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 44s
Build and Release FEDEO / build-and-release (push) Successful in 6m7s
Reviewed-on: #227
2026-09-23 16:15:44 +00:00
7e9f4409f6 Merge pull request 'dev' (#226) from dev into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 33s
Build and Release FEDEO / build-and-release (push) Successful in 6m10s
Reviewed-on: #226
2026-09-23 14:57:40 +00:00
2e63af1aa2 Merge pull request 'fix(release): stream large migration checksums from git' (#225) from flfeders/codex/release-migration-checksums into main
All checks were successful
Build and Release FEDEO / verify (push) Successful in 25s
Build and Release FEDEO / build-and-release (push) Successful in 5m59s
Reviewed-on: #225
2026-09-23 14:09:57 +00:00
5ebd2d508c Merge pull request 'fix(release): exclude legacy main history from commit checks' (#224) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Successful in 23s
Build and Release FEDEO / build-and-release (push) Failing after 5m57s
Reviewed-on: #224
2026-09-23 13:03:36 +00:00
9128fbb165 Merge pull request 'fix(ci): build dev images without repository write access' (#221) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Failing after 26s
Build and Release FEDEO / build-and-release (push) Has been skipped
Reviewed-on: #221
2026-09-20 16:25:38 +00:00
8473221c13 Merge pull request '3.0.0' (#220) from dev into main
Some checks failed
Build and Release FEDEO / verify (push) Failing after 22s
Build and Release FEDEO / build-and-release (push) Has been skipped
Reviewed-on: #220
2026-09-20 16:10:46 +00:00
e7554fa2cc .gitea/ISSUE_TEMPLATE/feature_request.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-22 17:42:28 +00:00
7c1fabf58a .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-22 17:40:58 +00:00
1203b6cbd1 .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 16s
2026-01-15 11:39:03 +00:00
525f2906fb .gitea/ISSUE_TEMPLATE/feature_request.md aktualisiert
Some checks failed
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
2026-01-15 11:38:50 +00:00
b105382abf .gitea/ISSUE_TEMPLATE/bug_report.md aktualisiert
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 16s
Build and Push Docker Images / build-frontend (push) Successful in 15s
2026-01-15 11:38:00 +00:00
b1cdec7d17 Merge pull request 'Added feature request template' (#62) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #62
2026-01-15 11:31:57 +00:00
f1d512b2e5 Merge pull request 'dev' (#61) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 17s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #61
2026-01-15 11:29:15 +00:00
db21b43120 Merge pull request 'dev' (#40) from dev into main
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 18s
Build and Push Docker Images / build-frontend (push) Successful in 16s
Reviewed-on: #40
2026-01-08 22:21:06 +00:00
5 changed files with 67 additions and 46 deletions

View File

@@ -2,37 +2,18 @@
name: 🐛 Bug Report name: 🐛 Bug Report
about: Erstelle einen Bericht, um uns zu helfen, das Projekt zu verbessern. about: Erstelle einen Bericht, um uns zu helfen, das Projekt zu verbessern.
title: '[BUG] ' title: '[BUG] '
labels: bug labels: Problem
assignees: '' assignees: ''
--- ---
**Beschreibung** **Beschreibung**
Eine klare und prägnante Beschreibung des Fehlers.
**Reproduktion** **Reproduktion**
Schritte, um den Fehler zu reproduzieren:
Entweder:
1. Gehe zu '...'
2. Klicke auf '...'
3. Scrolle runter zu '...'
4. Siehe Fehler
Oder Link zur Seite
**Erwartetes Verhalten**
Eine klare Beschreibung dessen, was du erwartet hast.
**Screenshots** **Screenshots**
Falls zutreffend, füge hier Screenshots oder Gifs hinzu, um das Problem zu verdeutlichen.
**Achtung: Achte bitte auf Datenschutz deiner Daten sowie der Daten deiner Kunden. Sollten ein Screenshot nur mit Daten möglich sein, schwärze diese bitte vor dem Upload.** **Achtung: Achte bitte auf Datenschutz deiner Daten sowie der Daten deiner Kunden. Sollten ein Screenshot nur mit Daten möglich sein, schwärze diese bitte vor dem Upload.**
**Umgebung:**
- Betriebssystem: [z.B. Windows, macOS, Linux]
- Browser / Version (falls relevant): [z.B. Chrome 120]
- Projekt-Version: [z.B. v1.0.2]
**Zusätzlicher Kontext**
Füge hier alle anderen Informationen zum Problem hinzu.

View File

@@ -2,19 +2,16 @@
name: ✨ Feature Request name: ✨ Feature Request
about: Schlage eine Idee für dieses Projekt vor. about: Schlage eine Idee für dieses Projekt vor.
title: '[FEATURE] ' title: '[FEATURE] '
labels: enhancement labels: Funktionswunsch
assignees: '' assignees: ''
--- ---
**Ist dein Feature-Wunsch mit einem Problem verbunden?** **Ist dein Feature-Wunsch mit einem Problem verbunden?**
Eine klare Beschreibung des Problems (z.B. "Ich bin immer genervt, wenn...").
**Lösungsvorschlag** **Lösungsvorschlag**
Eine klare Beschreibung dessen, was du dir wünschst und wie es funktionieren soll.
**Alternativen** **Alternativen**
Hast du über alternative Lösungen oder Workarounds nachgedacht?
**Zusätzlicher Kontext**
Hier ist Platz für weitere Informationen, Skizzen oder Beispiele von anderen Tools.

View File

@@ -10,8 +10,6 @@ import { TimeService, authorize } from '../src/modules/time-v2/service';
import { TimeMigration, previewLegacy } from '../src/modules/time-v2/migration'; import { TimeMigration, previewLegacy } from '../src/modules/time-v2/migration';
import { legacySpans, installTimeCompatibility, legacyEvent } from '../src/modules/time-v2/compatibility'; import { legacySpans, installTimeCompatibility, legacyEvent } from '../src/modules/time-v2/compatibility';
import timeV2Routes from '../src/routes/staff/time-v2'; import timeV2Routes from '../src/routes/staff/time-v2';
import { timeSpanInput } from '../../frontend/utils/timeSpanInput';
import { staffTimeRows, workingMinutes } from '../../frontend/utils/staffTimeSpans';
const at = (day: string, time: string) => `${day}T${time}:00Z`; const at = (day: string, time: string) => `${day}T${time}:00Z`;
const work = (start = '2026-10-01T06:00:00Z', end: string | null = '2026-10-01T14:30:00Z') => normalizeSpan({ type: 'work', started_at: start, ended_at: end, const work = (start = '2026-10-01T06:00:00Z', end: string | null = '2026-10-01T14:30:00Z') => normalizeSpan({ type: 'work', started_at: start, ended_at: end,
breaks: end ? [{ started_at: '2026-10-01T10:00:00Z', ended_at: '2026-10-01T10:30:00Z' }] : [] }); breaks: end ? [{ started_at: '2026-10-01T10:00:00Z', ended_at: '2026-10-01T10:30:00Z' }] : [] });
@@ -189,19 +187,18 @@ test('HTTP routes: validation, permissions, compatibility and migration conflict
await f.close(); await f.close();
} }
}); });
test('editing repeated local times preserves the original instant and rejects ambiguous new inputs', () => { test('legacy compatibility keeps paused attendance on both work and pause segments', () => {
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T01:15:00.000Z'), '2026-10-25T01:15:00.000Z');
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T00:15:00.000Z'), '2026-10-25T00:15:00.000Z');
assert.throws(() => timeSpanInput('2026-10-25T02:15', 'Europe/Berlin'), /zweimal/);
assert.throws(() => timeSpanInput('2026-03-29T02:15', 'Europe/Berlin'), /existiert nicht/);
assert.equal(timeSpanInput('2026-10-25T01:15', 'UTC'), '2026-10-25T01:15:00.000Z');
});
test('dashboard keeps a paused attendance active and freezes its net working duration', () => {
const s = work(undefined, null); s.id = randomUUID(); s.user_id = randomUUID(); const s = work(undefined, null); s.id = randomUUID(); s.user_id = randomUUID();
s.breaks = [{ started_at: '2026-10-01T10:00:00Z', ended_at: null }]; s.breaks = [{ started_at: '2026-10-01T10:00:00Z', ended_at: null }];
const entries = staffTimeRows(legacySpans([s]),s.user_id,Date.parse('2026-10-01T11:00:00Z')); const segments = legacySpans([s]);
assert.equal(entries.length,1); assert.equal(entries[0].type,'work'); assert.equal(segments.length, 2);
assert.equal((entries[0] as any).paused,true);assert.equal(entries[0].stopped_at,null); assert.equal(segments[0].type, 'work');
assert.equal(workingMinutes(entries[0],Date.parse('2026-10-01T12:00:00Z')),240); assert.equal(segments[0].endedAt, s.breaks[0].started_at);
assert.equal(segments[1].type, 'pause');
assert.equal(segments[1].endedAt, null);
for (const segment of segments) {
assert.equal(segment.model, 'spans-v2');
assert.equal(segment.id, s.id);
assert.deepEqual(segment.attendance, s);
}
}); });

View File

@@ -13,7 +13,7 @@ ARG FEDEO_VERSION=0.0.0-dev
ARG FEDEO_REVISION=unknown ARG FEDEO_REVISION=unknown
ENV FEDEO_VERSION=$FEDEO_VERSION ENV FEDEO_VERSION=$FEDEO_VERSION
ENV FEDEO_REVISION=$FEDEO_REVISION ENV FEDEO_REVISION=$FEDEO_REVISION
RUN npm run build RUN node --test tests/time-v2.test.cjs && npm run build
# --- Stage 2: Runtime --- # --- Stage 2: Runtime ---
FROM node:22-alpine AS runner FROM node:22-alpine AS runner

View File

@@ -0,0 +1,46 @@
const assert = require('node:assert/strict')
const test = require('node:test')
const fs = require('node:fs')
const vm = require('node:vm')
const ts = require('typescript')
function loadUtility(name) {
const source = fs.readFileSync(`${__dirname}/../utils/${name}.ts`, 'utf8')
const { outputText } = ts.transpileModule(source, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2021 },
})
const exports = {}
vm.runInNewContext(outputText, { exports })
return exports
}
const { timeSpanInput } = loadUtility('timeSpanInput')
const { staffTimeRows, workingMinutes } = loadUtility('staffTimeSpans')
test('editing repeated local times preserves the original instant and rejects ambiguous new inputs', () => {
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T01:15:00.000Z'), '2026-10-25T01:15:00.000Z');
assert.equal(timeSpanInput('2026-10-25T02:15', 'Europe/Berlin', '2026-10-25T00:15:00.000Z'), '2026-10-25T00:15:00.000Z');
assert.throws(() => timeSpanInput('2026-10-25T02:15', 'Europe/Berlin'), /zweimal/);
assert.throws(() => timeSpanInput('2026-03-29T02:15', 'Europe/Berlin'), /existiert nicht/);
assert.equal(timeSpanInput('2026-10-25T01:15', 'UTC'), '2026-10-25T01:15:00.000Z');
});
test('dashboard keeps a paused attendance active and freezes its net working duration', () => {
const attendance = {
id: 'attendance-1', user_id: 'user-1', type: 'work', status: 'factual',
started_at: '2026-10-01T06:00:00Z', ended_at: null,
breaks: [{ started_at: '2026-10-01T10:00:00Z', ended_at: null }],
}
const base = { id: attendance.id, model: 'spans-v2', attendance }
const segments = [
{ ...base, type: 'work', startedAt: attendance.started_at, endedAt: attendance.breaks[0].started_at },
{ ...base, type: 'pause', startedAt: attendance.breaks[0].started_at, endedAt: null },
]
const entries = staffTimeRows(segments, attendance.user_id, Date.parse('2026-10-01T11:00:00Z'))
assert.equal(entries.length, 1)
assert.equal(entries[0].type, 'work')
assert.equal(entries[0].paused, true)
assert.equal(entries[0].stopped_at, null)
assert.equal(entries[0].duration_minutes, 240)
assert.equal(workingMinutes(entries[0], Date.parse('2026-10-01T12:00:00Z')), 240)
})