Compare commits

..

107 Commits

Author SHA1 Message Date
Docker Config Backup
2b26dd17f8 Complete CA and CB column styling with borders and backgrounds
- Add left borders to CB column (CB2-CB22 and CB24-CB27, excluding CB23)
- Apply matching background colors to CA column (#FCD5B4 for rows 7-9, #D9D9D9 alternating)
- Add dotted top borders to CA column for employee rows (CA8-CA27 excluding CA23/24)
- Ensure solid top borders on CA23 and CA24 for section separators
- Add top borders to CA28 for complete section structure
- Maintain visual consistency between main table and additional columns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-08 12:34:19 +02:00
Docker Config Backup
cb1901af3f Add unformatted CB column and complete CA border structure
- Add completely unformatted CB column at rightmost position
- Update all styling loops to exclude CB column from formatting
- Fix day names row borders to exclude CB from styling
- Add CB6 formatting removal to ensure clean appearance
- Complete CA column border structure with top borders on CA24 and CA28
- Maintain clean separation between formatted (CA) and unformatted (CB) columns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-06 07:53:52 +02:00
Docker Config Backup
38d88127ba Enhance spreadsheet styling with comprehensive border system and formatting
- Add contextmenu fix to prevent TypeError
- Implement complete border system with top/left borders for all header rows
- Add dotted borders for employee rows (rows 8+)
- Create alternating row backgrounds (#D9D9D9) for better readability
- Add section separators at rows 23-24 and 28
- Implement background colors for rows 7-9 (#FCD5B4)
- Add day column separators (B,D,F,H etc.) from row 6 to end
- Create merged cell CA2:CA6 with proper borders
- Fix first row rotation for all cells including weekend merged cells
- Remove borders at section breaks for clean visual separation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-05 07:51:01 +02:00
Docker Config Backup
158c9f5375 Final auto-save before shutdown
Auto-saved at 2025-07-31 13:42:49

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 13:42:49 +02:00
Docker Config Backup
ec8f51ebb1 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 13:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 13:24:37 +02:00
Docker Config Backup
ec1168308c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 12:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 12:54:37 +02:00
Docker Config Backup
5a3c628583 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 12:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 12:24:37 +02:00
Docker Config Backup
a84f5d755e Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 11:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 11:54:37 +02:00
Docker Config Backup
bef574b0b5 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 11:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 11:24:37 +02:00
Docker Config Backup
c4e2f153ff Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 10:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 10:54:37 +02:00
Docker Config Backup
b562297e58 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 10:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 10:24:37 +02:00
Docker Config Backup
b182016b90 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 09:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 09:54:37 +02:00
Docker Config Backup
15137a50bf Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 09:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 09:24:37 +02:00
Docker Config Backup
72bc6ff360 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 08:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 08:54:37 +02:00
Docker Config Backup
2721e2a037 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 08:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 08:24:37 +02:00
Docker Config Backup
68c52ae8b6 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 07:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 07:54:37 +02:00
Docker Config Backup
6add9399f8 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 07:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 07:24:37 +02:00
Docker Config Backup
c43f2ca1af Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 06:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 06:54:37 +02:00
Docker Config Backup
6dd08cd528 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 06:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 06:24:37 +02:00
Docker Config Backup
4255f872ae Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 05:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 05:54:37 +02:00
Docker Config Backup
c6f63d0641 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 05:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 05:24:37 +02:00
Docker Config Backup
896ffdc2a7 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 04:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 04:54:37 +02:00
Docker Config Backup
5bff9b7d78 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 04:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 04:24:37 +02:00
Docker Config Backup
9faa573186 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 03:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 03:54:37 +02:00
Docker Config Backup
560c3de82e Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 03:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 03:24:37 +02:00
Docker Config Backup
396a644447 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 02:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 02:54:37 +02:00
Docker Config Backup
05c3976f8d Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 02:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 02:24:37 +02:00
Docker Config Backup
d385a874f3 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 01:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 01:54:37 +02:00
Docker Config Backup
09d20b0986 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 01:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 01:24:37 +02:00
Docker Config Backup
0238f924e1 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 00:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 00:54:37 +02:00
Docker Config Backup
f33b53eb3e Save before creating restore point: Periodic backup
Auto-saved at 2025-07-31 00:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 00:24:37 +02:00
Docker Config Backup
459199888c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 23:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 23:54:37 +02:00
Docker Config Backup
b50be44798 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 23:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 23:24:37 +02:00
Docker Config Backup
8991f7628f Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 22:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 22:54:37 +02:00
Docker Config Backup
3d7b9817a9 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 22:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 22:24:37 +02:00
Docker Config Backup
924e77302b Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 21:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 21:54:37 +02:00
Docker Config Backup
778d52dacb Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 21:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 21:24:37 +02:00
Docker Config Backup
1770dd014c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 20:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 20:54:37 +02:00
Docker Config Backup
31c05ee3c3 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 20:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 20:24:37 +02:00
Docker Config Backup
09f2ab2d57 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 19:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 19:54:37 +02:00
Docker Config Backup
ea26dd1e90 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 19:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 19:24:37 +02:00
Docker Config Backup
8389bd68df Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 18:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 18:54:37 +02:00
Docker Config Backup
f38a757b65 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 18:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 18:24:37 +02:00
Docker Config Backup
e0fda2819c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 17:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 17:54:37 +02:00
Docker Config Backup
ec73785754 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 17:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 17:24:37 +02:00
Docker Config Backup
5915c1fd16 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 16:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 16:54:37 +02:00
Docker Config Backup
1d121f5a32 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 16:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 16:24:37 +02:00
Docker Config Backup
22da72ce18 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 15:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 15:54:37 +02:00
Docker Config Backup
9e1458ce62 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 15:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 15:24:37 +02:00
Docker Config Backup
39d61e916c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 14:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 14:54:37 +02:00
Docker Config Backup
5071f574e7 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 14:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 14:24:37 +02:00
Docker Config Backup
24e3341802 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 13:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 13:54:37 +02:00
Docker Config Backup
2110de81c4 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 13:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 13:24:37 +02:00
Docker Config Backup
11aac2b8c2 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 12:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 12:54:37 +02:00
Docker Config Backup
d390613a1c Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 12:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 12:24:37 +02:00
Docker Config Backup
8aca9d2425 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 11:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 11:54:37 +02:00
Docker Config Backup
809482259f Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 11:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 11:24:37 +02:00
Docker Config Backup
cec8e47eea Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 10:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 10:54:37 +02:00
Docker Config Backup
4258c9e553 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 10:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 10:24:37 +02:00
Docker Config Backup
d139072aed Auto-save: Updated app/layout.tsx
Auto-saved at 2025-07-30 10:08:28

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 10:08:28 +02:00
Docker Config Backup
da6bd84a45 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 09:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 09:54:37 +02:00
Docker Config Backup
b22b12918e Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 09:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 09:24:37 +02:00
Docker Config Backup
318fef77aa Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 08:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 08:54:37 +02:00
Docker Config Backup
5e332aac05 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 08:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 08:24:37 +02:00
Docker Config Backup
4322dfbe54 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 07:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 07:54:37 +02:00
Docker Config Backup
1cfbb0b72f Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 07:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 07:24:37 +02:00
Docker Config Backup
1d844ad6f9 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 06:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 06:54:37 +02:00
Docker Config Backup
adf8eb3021 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 06:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 06:24:37 +02:00
Docker Config Backup
590fafb054 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 05:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 05:54:37 +02:00
Docker Config Backup
75bf66d629 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 05:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 05:24:37 +02:00
Docker Config Backup
ca212b9e3d Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 04:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 04:54:37 +02:00
Docker Config Backup
bb34d168f6 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 04:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 04:24:37 +02:00
Docker Config Backup
a7b37690b4 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 03:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 03:54:37 +02:00
Docker Config Backup
83b8d8ba59 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 03:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 03:24:37 +02:00
Docker Config Backup
2dac8a0679 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 02:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 02:54:37 +02:00
Docker Config Backup
3596f64ce8 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 02:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 02:24:37 +02:00
Docker Config Backup
fc10e3addc Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 01:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 01:54:37 +02:00
Docker Config Backup
d3c6d6acfe Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 01:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 01:24:37 +02:00
Docker Config Backup
f97a054b7d Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 00:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 00:54:37 +02:00
Docker Config Backup
90c1c2a4f8 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-30 00:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 00:24:37 +02:00
Docker Config Backup
a287b75a8f Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 23:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 23:54:37 +02:00
Docker Config Backup
a021750956 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 23:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 23:24:37 +02:00
Docker Config Backup
5c6788665f Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 22:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 22:54:37 +02:00
Docker Config Backup
ce8c01812b Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 22:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 22:24:37 +02:00
Docker Config Backup
a9932d4fd3 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 21:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 21:54:37 +02:00
Docker Config Backup
fa9eb62868 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 21:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 21:24:37 +02:00
Docker Config Backup
92e8ebabe1 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 20:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 20:54:37 +02:00
Docker Config Backup
daa1364069 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 20:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 20:24:37 +02:00
Docker Config Backup
40fb3e6761 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 19:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 19:54:37 +02:00
Docker Config Backup
2dde60e531 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 19:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 19:24:37 +02:00
Docker Config Backup
1773ed4af7 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 18:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 18:54:37 +02:00
Docker Config Backup
ca47d81d6b Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 18:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 18:24:37 +02:00
Docker Config Backup
d3bdffb8f1 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 17:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 17:54:37 +02:00
Docker Config Backup
2204310cec Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 17:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 17:24:37 +02:00
Docker Config Backup
5857be8dc6 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 16:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 16:54:37 +02:00
Docker Config Backup
8e3f09bb7d Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 16:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 16:24:37 +02:00
Docker Config Backup
2fc1eab591 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 15:54:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 15:54:37 +02:00
Docker Config Backup
35762bc4f4 Save before creating restore point: Periodic backup
Auto-saved at 2025-07-29 15:24:37

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 15:24:37 +02:00
Docker Config Backup
e6c22ad29b Auto-save: Updated components/timeshift-spreadsheet.tsx
Auto-saved at 2025-07-29 15:01:45

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 15:01:45 +02:00
Docker Config Backup
7e808f6528 Save before creating restore point: Session start
Auto-saved at 2025-07-29 14:54:42

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:54:42 +02:00
Docker Config Backup
d702a2df7f Final auto-save before shutdown
Auto-saved at 2025-07-29 14:54:35

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:54:35 +02:00
Docker Config Backup
e44e1ffb8a Auto-save: Updated components/timeshift-spreadsheet.tsx
Auto-saved at 2025-07-29 14:35:46

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:35:46 +02:00
Docker Config Backup
fb86c59413 Set up PM2 auto-commit service with monitoring and startup scripts
Auto-saved at 2025-07-29 14:31:25

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:31:25 +02:00
Docker Config Backup
191eeca57f Auto-save: Updated components/test-component.tsx
Auto-saved at 2025-07-29 14:31:08

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:31:08 +02:00
Docker Config Backup
8ed2967f6f Save before creating restore point: Session start
Auto-saved at 2025-07-29 14:27:28

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:27:28 +02:00
Docker Config Backup
58eb8c169b Save before creating restore point: Before implementing auto-commit system
Auto-saved at 2025-07-29 14:24:49

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:24:49 +02:00
Docker Config Backup
0ead94ac8d Add Práce mimo směnu column with proper layout
- Add separator column and Práce mimo směnu column to timeshift spreadsheet
- Implement vertical merging for Práce mimo směnu across rows 2-6
- Add proper styling with borders and rotated text
- Exclude separator/práce columns from regular merging logic
- Add test component for debugging

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-29 14:23:08 +02:00
15 changed files with 2009 additions and 58 deletions

174
AUTO-COMMIT-README.md Normal file
View File

@@ -0,0 +1,174 @@
# Auto-Commit System for Timeshift Project
This system automatically saves your work to git to prevent losing changes when Claude gets restarted or when making experimental changes.
## 🚀 Quick Start
### Start Auto-Watch (Recommended)
```bash
npm run watch-commit
```
This will automatically commit changes every 30 seconds when files are modified.
### Manual Commands
```bash
# Save current work immediately
npm run save "Your commit message"
# Create a restore point before major changes
npm run restore-point "Before major refactor"
# List all restore points
./auto-commit.sh list
# Clean old restore points (keeps last 10)
./auto-commit.sh cleanup
```
## 📋 How It Works
### Automatic Commits
- **File Watcher**: Monitors `components/`, `app/`, `lib/`, `styles/` directories
- **Smart Delay**: Waits 30 seconds after last change before committing
- **Rate Limiting**: Max 10 commits per hour to avoid spam
- **File Types**: Watches `.tsx`, `.ts`, `.js`, `.jsx`, `.css`, `.scss`, `.json` files
### Restore Points
- **Branches**: Creates timestamped branches like `restore-point-20250129-143022`
- **Automatic**: Creates restore points on startup and every 30 minutes
- **Manual**: Create before risky changes with `npm run restore-point "description"`
## 🔧 Features
### Auto-Commit Script Features
✅ Automatic timestamped commits
✅ Descriptive commit messages
✅ Rate limiting to prevent spam
✅ Restore point creation
✅ Cleanup of old restore points
✅ Git status checking
### File Watcher Features
✅ Real-time file monitoring
✅ Smart batching of changes
✅ Graceful shutdown handling
✅ Periodic restore points
✅ Console logging for transparency
## 📚 Usage Examples
### Starting Your Work Session
```bash
# Start the auto-commit watcher
npm run watch-commit
# In another terminal, start development
npm run dev
```
### Before Making Risky Changes
```bash
# Create a restore point
npm run restore-point "Before implementing new feature"
# Make your changes...
# Files are auto-committed as you work
# If something breaks, restore with:
git checkout restore-point-20250129-143022
```
### Manual Saves
```bash
# Quick save
npm run save
# Save with custom message
npm run save "Fixed spreadsheet column alignment"
```
### Managing Restore Points
```bash
# List all restore points
./auto-commit.sh list
# Clean up old ones (keeps last 10)
./auto-commit.sh cleanup
```
## 🎯 Benefits
1. **Never Lose Work**: Changes are saved every 30 seconds automatically
2. **Easy Recovery**: Restore points let you go back to working states
3. **Experiment Safely**: Try changes knowing you can always revert
4. **Claude Restarts**: No more losing progress when Claude session ends
5. **Version History**: Full git history of all changes with timestamps
## ⚙️ Configuration
### Modify Watch Settings
Edit `watch-and-commit.js`:
```javascript
const COMMIT_DELAY = 30000; // 30 seconds
const MAX_COMMITS_PER_HOUR = 10;
const WATCH_DIRS = ['components', 'app', 'lib', 'styles'];
```
### Modify Auto-Commit Behavior
Edit `auto-commit.sh` to change commit message format or add custom logic.
## 🛟 Recovery Scenarios
### Claude Gets Restarted
Your work is automatically saved! Just continue from where you left off.
### Experimental Changes Break Things
```bash
# List restore points to find a good one
./auto-commit.sh list
# Checkout the restore point
git checkout restore-point-20250129-143022
# Or continue from main with your auto-commits
git checkout main
git log --oneline -10 # See recent auto-commits
```
### Need to Go Back a Few Commits
```bash
# See recent commits
git log --oneline -10
# Reset to a specific commit (keep files)
git reset --soft HEAD~3
# Or create a new branch from specific commit
git checkout -b fix-attempt abc1234
```
## 🚦 Status Indicators
The watcher shows:
- 🔍 **Started**: Auto-commit watcher is running
- 📝 **File changed**: A file was modified
- 🔄 **Performing auto-commit**: About to save changes
-**Auto-commit successful**: Changes saved
- 🔖 **Creating restore point**: Making a backup branch
- ⏸️ **Rate limit reached**: Too many commits, pausing
## 🎮 Quick Reference
| Command | Purpose |
|---------|---------|
| `npm run watch-commit` | Start automatic file watching |
| `npm run save` | Immediate manual commit |
| `npm run restore-point` | Create backup branch |
| `./auto-commit.sh list` | Show restore points |
| `./auto-commit.sh cleanup` | Remove old restore points |
| `git checkout restore-point-XXXXXX` | Restore to backup |
| `git log --oneline -10` | See recent commits |
---
**Pro Tip**: Always run `npm run watch-commit` when starting work with Claude to ensure nothing gets lost! 🛡️

103
PM2-QUICK-REFERENCE.md Normal file
View File

@@ -0,0 +1,103 @@
# PM2 Auto-Commit Service - Quick Reference
## ✅ Service Status: RUNNING
The auto-commit watcher is now running as a PM2 background service!
## 🚀 Quick Commands
### Service Management
```bash
# Check service status
npm run pm2:status
# View auto-commit logs
npm run services:logs
# Stop auto-commit service
npm run services:stop
# Start auto-commit service
npm run services:start
# Restart auto-commit service
./start-services.sh restart
```
### Manual Operations
```bash
# Save changes immediately
npm run save "Your message"
# Create restore point
npm run restore-point "Before big changes"
# List restore points
./auto-commit.sh list
```
## 📊 Monitoring
### Real-time Monitoring
```bash
# PM2 monitoring dashboard
npm run pm2:monit
# Live log streaming
pm2 logs timeshift-auto-commit
```
### Log Files
- **Output**: `/home/klas/timeshift/logs/auto-commit.out.log`
- **Errors**: `/home/klas/timeshift/logs/auto-commit.error.log`
- **Combined**: `/home/klas/timeshift/logs/auto-commit.log`
## ⚙️ How It Works
1. **File Watching**: Monitors `components/`, `app/`, `lib/` directories
2. **Smart Delay**: Waits 30 seconds after last change
3. **Auto-Commit**: Creates timestamped git commits
4. **Rate Limiting**: Max 10 commits per hour
5. **Restore Points**: Creates backup branches every 30 minutes
## 🛡️ Backup & Recovery
### Automatic Backups
- ✅ Auto-commits every 30 seconds when files change
- ✅ Restore points every 30 minutes
- ✅ Session restore point on startup
### Manual Recovery
```bash
# See all restore points
./auto-commit.sh list
# Restore to specific point
git checkout restore-point-20250729-142449
# Go back to main
git checkout main
# See recent auto-commits
git log --oneline -10
```
## 🔧 Process Info
- **Service Name**: `timeshift-auto-commit`
- **Process ID**: Check with `npm run pm2:status`
- **Auto-restart**: Yes (if crashes)
- **Max Memory**: 200MB limit
- **Log Rotation**: Managed by PM2
## 🎯 Benefits Achieved
**No more lost work** - Changes saved every 30 seconds
**Claude restart proof** - Survives session restarts
**Background operation** - Runs independently
**Auto-recovery** - PM2 restarts if crashes
**Full monitoring** - Logs and status tracking
**Easy management** - Simple npm commands
---
**🎉 Success**: Your work is now automatically protected!
The service is running in the background and will continue even if Claude restarts.

View File

@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "161",
description: "TKB Timeshift Schedule Management Application",
};
export default function RootLayout({

114
auto-commit.sh Executable file
View File

@@ -0,0 +1,114 @@
#!/bin/bash
# Auto-commit script for timeshift project
# Usage: ./auto-commit.sh [message]
set -e
# Function to auto-commit changes
auto_commit() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Check if there are any changes
if [[ -n $(git status --porcelain) ]]; then
echo "🔄 Auto-committing changes at $timestamp"
# Add all changes
git add .
# Create commit message
if [[ -z "$message" ]]; then
message="Auto-commit: Save work in progress"
fi
# Commit with timestamp
git commit -m "$(cat <<EOF
$message
Auto-saved at $timestamp
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"
echo "✅ Changes committed successfully"
# Auto-push to remote repository
echo "📤 Pushing to remote repository..."
if git push origin main 2>/dev/null; then
echo "✅ Successfully pushed to remote"
else
echo "⚠️ Push failed (remote may be unreachable)"
fi
# Show short log
git log --oneline -3
else
echo "📝 No changes to commit at $timestamp"
fi
}
# Function to create a safe restore point
create_restore_point() {
local description="$1"
local branch_name="restore-point-$(date '+%Y%m%d-%H%M%S')"
echo "🔖 Creating restore point: $branch_name"
# Commit current changes first
auto_commit "Save before creating restore point: $description"
# Create a new branch as restore point
git branch "$branch_name"
echo "✅ Restore point created: $branch_name"
echo "📋 To restore later, run: git checkout $branch_name"
}
# Function to show available restore points
list_restore_points() {
echo "📋 Available restore points:"
git branch | grep "restore-point-" | sed 's/^..//' | sort -r
}
# Function to clean old restore points (keep last 10)
cleanup_restore_points() {
echo "🧹 Cleaning old restore points (keeping last 10)..."
git branch | grep "restore-point-" | sed 's/^..//' | sort -r | tail -n +11 | while read branch; do
git branch -D "$branch" 2>/dev/null && echo "🗑️ Deleted old restore point: $branch"
done
}
# Main script logic
case "$1" in
"commit")
auto_commit "$2"
;;
"restore-point")
create_restore_point "$2"
;;
"list")
list_restore_points
;;
"cleanup")
cleanup_restore_points
;;
*)
echo "📚 Auto-commit utility for timeshift project"
echo ""
echo "Usage:"
echo " $0 commit [message] - Auto-commit current changes"
echo " $0 restore-point [desc] - Create a restore point branch"
echo " $0 list - List available restore points"
echo " $0 cleanup - Clean old restore points"
echo ""
echo "Examples:"
echo " $0 commit 'Fixed spreadsheet layout'"
echo " $0 restore-point 'Before major refactor'"
echo ""
auto_commit "$1"
;;
esac

View File

@@ -0,0 +1,32 @@
"use client"
import * as React from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
interface TestComponentProps {
teamId: string
teamName: string
}
export function TestComponent({ teamId, teamName }: TestComponentProps) {
return (
<Card className="w-full">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="flex items-center gap-2">{teamName} - Test Component</CardTitle>
<CardDescription>Testing if React components load properly (Team ID: {teamId})</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<div className="border rounded-lg p-4">
<p>This is a test component to verify React is working.</p>
<p>If you can see this, the basic React setup is functional.</p>
<p>Auto-commit test: {new Date().toISOString()}</p>
</div>
</CardContent>
</Card>
)
}

View File

@@ -12,9 +12,13 @@ interface TimeshiftSpreadsheetProps {
teamName: string
}
export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpreadsheetProps) {
export function TimeshiftSpreadsheet({ teamId, teamName }: TimeshiftSpreadsheetProps) {
const spreadsheetRef = React.useRef<HTMLDivElement>(null)
const jspreadsheetInstance = React.useRef<unknown>(null)
const isActiveRef = React.useRef<boolean>(true)
const isMergingRef = React.useRef<boolean>(false)
const isInitializingRef = React.useRef<boolean>(false)
const initTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)
const currentDate = new Date()
const [selectedMonth, setSelectedMonth] = React.useState<string>((currentDate.getMonth() + 1).toString())
const [selectedYear, setSelectedYear] = React.useState<string>(currentDate.getFullYear().toString())
@@ -55,7 +59,7 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
const yearRow = ["rok"]
const monthRow = ["měsíc"]
const dateRow = ["den"]
const shiftRow = [`Pohotovost ${_teamId.toUpperCase()}`]
const shiftRow = [`Pohotovost ${teamId.toUpperCase()}`]
// Generate columns for each day from prevMonthStart to nextMonthEnd
const currentDate = new Date(prevMonthStart)
@@ -80,7 +84,7 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
console.log("Generated", dayCount, "days of data")
// Complete employee data from Excel file
// Complete employee data from Excel file - cleaned up without empty rows, kontrolní řádek, and X BEZ zkušeností s VN
const employees = [
"Pauzer Libor (all in one)",
"Vörös Pavel (NN)",
@@ -98,10 +102,21 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
"Zábranský Petr (NN)",
"Žemlička Miroslav (NN)",
"Teslík Hynek (NN)",
"X BEZ zkušeností s VN",
"Pohotovost IT"
"Pohotovost IT", // Header - will be made bold
"Vörös Pavel",
"Janouš Petr",
"Glaser Ondřej",
"Robert Štefan"
]
// Add two more columns to the right (CA is formatted, CB will be unformatted)
titleRow.push("", "")
dayNameRow.push("", "")
yearRow.push("", "")
monthRow.push("", "")
dateRow.push("", "")
shiftRow.push("", "")
const employeeRows = employees.map(name => {
const row = [name]
// Add empty cells for each day/night pair
@@ -111,7 +126,7 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
return row
})
const result = [titleRow, dayNameRow, yearRow, monthRow, dateRow, shiftRow, [""], ...employeeRows]
const result = [titleRow, dayNameRow, yearRow, monthRow, dateRow, shiftRow, ...employeeRows]
console.log("Generated", result.length, "rows with", result[0]?.length, "columns")
console.log("Title row:", titleRow.slice(0, 10))
console.log("Day row:", dayNameRow.slice(0, 10))
@@ -119,7 +134,7 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
}
// Sample data for different teams (fallback)
const getTeamData = (_teamId: string) => {
const getTeamData = (teamId: string) => {
const baseData = [
["Employee", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
["John Smith", "08:00-16:00", "08:00-16:00", "08:00-16:00", "08:00-16:00", "08:00-16:00", "OFF", "OFF"],
@@ -134,6 +149,34 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
React.useEffect(() => {
console.log("useEffect triggered - Month:", selectedMonth, "Year:", selectedYear, "Force:", forceUpdate)
// Clear any existing timeout
if (initTimeoutRef.current) {
console.log("CLEARING: existing timeout, debouncing useEffect")
clearTimeout(initTimeoutRef.current)
}
// Prevent multiple simultaneous initializations with immediate return
if (isInitializingRef.current) {
console.log("BLOCKED: useEffect - already initializing, skipping completely")
return
}
console.log("DEBOUNCING: useEffect with 100ms delay")
// Debounce the initialization to prevent rapid successive calls
initTimeoutRef.current = setTimeout(() => {
console.log("EXECUTING: debounced useEffect after delay")
// Double-check we're still not initializing (could have started between timeout set and execution)
if (isInitializingRef.current) {
console.log("BLOCKED: Still initializing at timeout execution")
return
}
isInitializingRef.current = true
isActiveRef.current = true
const loadJSpreadsheet = async () => {
console.log("Starting loadJSpreadsheet function")
@@ -197,10 +240,33 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
if (spreadsheetRef.current && jexcelLib) {
console.log("Initializing spreadsheet...")
// Clear previous instance
// Clear previous instance and reset any merge states
if (jspreadsheetInstance.current) {
console.log("Destroying previous instance")
jspreadsheetInstance.current.destroy()
try {
const instance = jspreadsheetInstance.current as any
// Clear any existing merges before destroying
if (instance.removeMerge && instance.getMerge) {
try {
const merges = instance.getMerge()
if (merges && Array.isArray(merges)) {
merges.forEach((merge: any) => {
try {
instance.removeMerge(merge.address)
} catch (e) {
// Ignore individual merge removal errors
}
})
}
} catch (e) {
// Ignore merge clearing errors
}
}
instance.destroy()
} catch (error) {
console.error("Error destroying instance:", error)
}
jspreadsheetInstance.current = null
}
// Use monthly data if month/year selected, otherwise use basic data
@@ -212,11 +278,11 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
console.log("Monthly data generated successfully")
} else {
console.log("Using basic team data")
data = getTeamData(_teamId)
data = getTeamData(teamId)
}
} catch (error) {
console.error("Error generating data:", error)
data = getTeamData(_teamId)
data = getTeamData(teamId)
}
console.log("Data generated:", data.length, "rows, first row:", data[0]?.length, "columns")
@@ -232,19 +298,59 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
// Generate styles for day/night shifts based on the Excel pattern
const styles: Record<string, string> = {}
if (selectedMonth && selectedYear) {
// Make day names row (row 2) taller
// Make first row (row 1) taller - 97px
for (let col = 0; col < (data[0]?.length || 0); col++) {
const colLetter = getExcelColumnName(col)
styles[`${colLetter}2`] = "height: 50px;"
styles[`${colLetter}1`] = "height: 97px;"
}
// Make day names row (row 2) taller and add top and left borders from column B onwards (except last three columns)
for (let col = 0; col < (data[0]?.length || 0); col++) {
const colLetter = getExcelColumnName(col)
if (col === 0) {
// First column (A) - just height
styles[`${colLetter}2`] = "height: 50px;"
} else if (colLetter === 'BZ' || colLetter === 'CA' || colLetter === 'CB') {
// Last three columns (BZ, CA, CB) - height only, no borders
styles[`${colLetter}2`] = "height: 50px;"
} else {
// All other columns (B onwards except BZ, CA, CB) - height + top and left borders
styles[`${colLetter}2`] = "height: 50px; border-top: 1px solid #000000; border-left: 1px solid #000000;"
}
}
// Add top border to year row (row 3) from B3 to end of table (excluding A3 and last columns)
for (let col = 1; col < (data[0]?.length || 0) - 2; col++) { // Start from column B (index 1), exclude CA and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}3`] || ""
styles[`${colLetter}3`] = existingStyle + " border-top: 1px solid #000000;"
}
// Add top border to shift row (row 6) from A6 to end of table (excluding last columns)
for (let col = 0; col < (data[0]?.length || 0) - 2; col++) { // Exclude CA and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}6`] || ""
styles[`${colLetter}6`] = existingStyle + " border-top: 1px solid #000000;"
}
// Add left borders to columns B onwards for rows 3, 4, 5 (year, month, day)
for (let row = 3; row <= 5; row++) {
for (let col = 1; col < (data[0]?.length || 0) - 2; col++) { // Start from column B (index 1), exclude CA and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " border-left: 1px solid #000000;"
}
}
// Style header rows
for (let col = 1; col < (data[0]?.length || 0); col++) {
const colLetter = getExcelColumnName(col)
// Preserve existing styles (including top border) and add background colors
const existingStyle = styles[`${colLetter}6`] || ""
if (col % 2 === 1) { // Day shifts (odd columns after first)
styles[`${colLetter}6`] = "background-color: #ffff00; font-weight: normal;" // Yellow for day, not bold
styles[`${colLetter}6`] = existingStyle + " background-color: #ffff00; font-weight: normal;" // Yellow for day, not bold
} else { // Night shifts (even columns after first)
styles[`${colLetter}6`] = "background-color: #00b0f0; font-weight: normal;" // Blue for night, not bold
styles[`${colLetter}6`] = existingStyle + " background-color: #00b0f0; font-weight: normal;" // Blue for night, not bold
}
}
@@ -255,17 +361,181 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
const colLetter = getExcelColumnName(col)
const nextColLetter = getExcelColumnName(col + 1)
// Weekend day name row (row 2) - merged cells
styles[`${colLetter}2`] = "background-color: #ffd966; height: 50px;" // Weekend day name with height
styles[`${nextColLetter}2`] = "background-color: #ffd966; height: 50px;"
// Weekend day name row (row 2) - merged cells with conditional borders
const hasBorders1 = colLetter !== 'BZ' && colLetter !== 'CA' && colLetter !== 'CB' ? " border-top: 1px solid #000000; border-left: 1px solid #000000;" : ""
const hasBorders2 = nextColLetter !== 'BZ' && nextColLetter !== 'CA' && nextColLetter !== 'CB' ? " border-top: 1px solid #000000; border-left: 1px solid #000000;" : ""
styles[`${colLetter}2`] = `background-color: #ffd966; height: 50px;${hasBorders1}` // Weekend day name with conditional borders
styles[`${nextColLetter}2`] = `background-color: #ffd966; height: 50px;${hasBorders2}`
// Weekend date columns (rows 3, 4, 5 - year, month, day)
for (let row = 3; row <= 5; row++) {
styles[`${colLetter}${row}`] = "background-color: #ffd966;" // Weekend date values
styles[`${nextColLetter}${row}`] = "background-color: #ffd966;" // Weekend date values
// Preserve existing styles (like borders) and add weekend background
const existingStyle1 = styles[`${colLetter}${row}`] || ""
const existingStyle2 = styles[`${nextColLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle1 + " background-color: #ffd966;" // Weekend date values
styles[`${nextColLetter}${row}`] = existingStyle2 + " background-color: #ffd966;" // Weekend date values
}
}
}
// Remove formatting specifically from BZ6, CA6, and CB6 cells
styles["BZ6"] = "" // Override any formatting for BZ6
styles["CA6"] = "" // Override any formatting for CA6
styles["CB6"] = "" // Override any formatting for CB6
// Remove top border from BZ3 cell
styles["BZ3"] = (styles["BZ3"] || "").replace(" border-top: 1px solid #000000;", "").replace("border-top: 1px solid #000000;", "")
// Add left border to BZ column from row 2 to the last employee row
const totalRows = data.length
const employeeStartRow = 7 // Row 7 is first employee (0-indexed: rows 1-6 are headers, no empty row)
for (let row = 2; row <= totalRows; row++) {
styles[`BZ${row}`] = (styles[`BZ${row}`] || "") + " border-left: 1px solid #000000;"
}
// Add dotted top borders to employee rows (starting from row 8) up to BY column
for (let row = 8; row <= totalRows; row++) {
for (let col = 0; col < (data[0]?.length || 0) - 3; col++) { // All columns except BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " border-top: 1px dotted #000000;"
}
}
// Make "Pohotovost IT" header bold (employee index 16, so row 23)
styles["A23"] = "font-weight: bold;" // "Pohotovost IT"
// Set background color for rows 7, 8, and 9 (excluding BZ, CA, and CB columns)
for (let row = 7; row <= 9; row++) {
for (let col = 0; col < (data[0]?.length || 0) - 3; col++) { // All columns except BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " background-color: #FCD5B4;"
}
}
// Add left borders to first column of each day (B, D, F, H, etc.) from row 6 to end of table
for (let row = 6; row <= totalRows; row++) {
for (let col = 1; col < (data[0]?.length || 0) - 3; col += 2) { // Start from B (index 1), step by 2, exclude BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " border-left: 1px solid #000000;"
}
}
// Add top border to row 28 from A to BY
for (let col = 0; col < (data[0]?.length || 0) - 3; col++) { // All columns except BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}28`] || ""
styles[`${colLetter}28`] = existingStyle + " border-top: 1px solid #000000;"
}
// Add alternating row background colors starting from row 10 (every odd row: 10,12,14,16,18,20,22,24,26)
for (let row = 10; row <= totalRows; row += 2) { // Start from 10, increment by 2
for (let col = 0; col < (data[0]?.length || 0) - 3; col++) { // All columns except BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " background-color: #D9D9D9;"
}
}
// Add top borders to rows 23 and 24 from A to BY
for (let row of [23, 24]) {
for (let col = 0; col < (data[0]?.length || 0) - 3; col++) { // All columns except BZ, CA, and CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}${row}`] || ""
styles[`${colLetter}${row}`] = existingStyle + " border-top: 1px solid #000000;"
}
}
// Remove left borders from row 23 (day column borders)
for (let col = 1; col < (data[0]?.length || 0) - 3; col += 2) { // Day columns: B, D, F, H, etc., exclude BZ, CA, CB
const colLetter = getExcelColumnName(col)
const existingStyle = styles[`${colLetter}23`] || ""
// Remove left border by replacing it with empty string
styles[`${colLetter}23`] = existingStyle.replace(" border-left: 1px solid #000000;", "").replace("border-left: 1px solid #000000;", "")
}
// Remove left border from BZ23
const existingBZ23Style = styles["BZ23"] || ""
styles["BZ23"] = existingBZ23Style.replace(" border-left: 1px solid #000000;", "").replace("border-left: 1px solid #000000;", "")
// Add top and left borders to merged cell CA2 (CA2:CA6)
const existingCA2Style = styles["CA2"] || ""
styles["CA2"] = existingCA2Style + " border-top: 1px solid #000000; border-left: 1px solid #000000;"
// Add left border to CA column from row 7 to 27 (excluding row 23)
for (let row = 7; row <= 27; row++) {
if (row !== 23) { // Skip row 23 where "Pohotovost IT" is located
const existingCAStyle = styles[`CA${row}`] || ""
styles[`CA${row}`] = existingCAStyle + " border-left: 1px solid #000000;"
}
}
// Add top border to CA23
const existingCA23Style = styles["CA23"] || ""
styles["CA23"] = existingCA23Style + " border-top: 1px solid #000000;"
// Add top border to CA24
const existingCA24Style = styles["CA24"] || ""
styles["CA24"] = existingCA24Style + " border-top: 1px solid #000000;"
// Add top border to CA28
const existingCA28Style = styles["CA28"] || ""
styles["CA28"] = existingCA28Style + " border-top: 1px solid #000000;"
// Add left border to CB column (CB2-CB22 and CB24-CB27, excluding CB23)
for (let row = 2; row <= 27; row++) {
if (row !== 23) { // Skip row 23 where "Pohotovost IT" is located
const existingCBStyle = styles[`CB${row}`] || ""
styles[`CB${row}`] = existingCBStyle + " border-left: 1px solid #000000;"
}
}
// Apply same background colors to CA column as applied to main table rows
// Background color for rows 7, 8, and 9 (same as main table)
for (let row = 7; row <= 9; row++) {
const existingCAStyle = styles[`CA${row}`] || ""
styles[`CA${row}`] = existingCAStyle + " background-color: #FCD5B4;"
}
// Alternating row background colors for CA column starting from row 10 (same as main table)
for (let row = 10; row <= totalRows; row += 2) { // Start from 10, increment by 2
if (row <= 27) { // Only apply to rows up to 27
const existingCAStyle = styles[`CA${row}`] || ""
styles[`CA${row}`] = existingCAStyle + " background-color: #D9D9D9;"
}
}
// Add dotted top borders to CA column for employee rows (starting from row 8, same as main table)
for (let row = 8; row <= 27; row++) {
// Skip rows 23 and 24 as they will get solid borders instead
if (row !== 23 && row !== 24) {
const existingCAStyle = styles[`CA${row}`] || ""
styles[`CA${row}`] = existingCAStyle + " border-top: 1px dotted #000000;"
}
}
// Ensure solid top borders on CA23 and CA24 (override any previous styling)
const existingCA23Style2 = styles["CA23"] || ""
styles["CA23"] = existingCA23Style2.replace(" border-top: 1px dotted #000000;", "") + " border-top: 1px solid #000000;"
const existingCA24Style2 = styles["CA24"] || ""
styles["CA24"] = existingCA24Style2.replace(" border-top: 1px dotted #000000;", "") + " border-top: 1px solid #000000;"
}
// Validate configuration before initializing
if (!data || data.length === 0) {
console.error("Data is empty or undefined:", data)
isInitializingRef.current = false
return
}
if (!columns || columns.length === 0) {
console.error("Columns is empty or undefined:", columns)
isInitializingRef.current = false
return
}
console.log("Initializing jspreadsheet with config:", {
@@ -275,66 +545,356 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
stylesCount: Object.keys(styles).length
})
jspreadsheetInstance.current = (jexcelLib as (el: HTMLElement, config: unknown) => unknown)(spreadsheetRef.current, {
data: data,
columns: columns,
const config = {
data,
columns,
minDimensions: [data[0]?.length || 8, Math.max(data.length + 3, 10)],
allowInsertRow: true,
allowInsertColumn: false,
allowDeleteRow: true,
allowDeleteColumn: false,
contextMenu: true,
contextMenu: false,
tableOverflow: true,
tableWidth: "100%",
tableHeight: "500px",
style: styles,
})
console.log("jspreadsheet initialized:", !!jspreadsheetInstance.current)
// Apply cell merges for header rows after initialization
if (jspreadsheetInstance.current && selectedMonth && selectedYear) {
const instance = jspreadsheetInstance.current as any
if (instance.setMerge) {
// Merge all pairs in rows 2, 3, 4, 5 (day names, year, month, day)
for (let row = 2; row <= 5; row++) {
for (let col = 1; col < (data[0]?.length || 0); col += 2) {
const colLetter = getExcelColumnName(col)
onchange: (instance: any, cell: HTMLElement, x: number, y: number, value: string) => {
console.log("onChange triggered:", { x, y, value, isMerging: isMergingRef.current })
// Skip onChange events during merging process to prevent infinite loops
if (isMergingRef.current) {
console.log("Skipping onChange during merge:", { x, y, value })
return
}
// Only process if component is still active
if (!isActiveRef.current || !jspreadsheetInstance.current) return
// Apply rotation to first row (y === 0) when text is entered
if (y === 0 || y === '0') {
console.log("First row change detected, applying rotation...", { x, y, value })
// Use requestAnimationFrame for better DOM timing
requestAnimationFrame(() => {
if (!isActiveRef.current || !spreadsheetRef.current) return
try {
// Correct syntax: setMerge(cellAddress, colspan, rowspan)
instance.setMerge(`${colLetter}${row}`, 2, 1) // 2 columns, 1 row
console.log(`Merged ${colLetter}${row} with 2 columns`)
const table = spreadsheetRef.current?.querySelector('.jexcel tbody')
if (table) {
const rows = table.querySelectorAll('tr')
if (rows[0]) {
const cells = rows[0].querySelectorAll('td')
const targetX = parseInt(String(x))
let targetCell = cells[targetX + 1] as HTMLElement // +1 because first cell is row number
console.log("Initial target cell found:", !!targetCell, "Cell display:", targetCell?.style.display, "Target X:", targetX)
// Handle both merged and non-merged cells
if (targetCell) {
// If target cell is hidden (part of a merge), find the visible merged cell
if (targetCell.style.display === 'none') {
console.log("🔍 Target cell is hidden, finding visible merged cell...")
// Look for visible merged cells that cover this position
let foundCell = null
// Search all visible cells to find which one covers our position
for (let i = 1; i < cells.length; i++) {
const cell = cells[i] as HTMLElement
if (cell && cell.style.display !== 'none' && cell.colSpan && cell.colSpan > 1) {
// Get the starting column of this merged cell
const cellIndex = i - 1 // Subtract 1 for row number cell
const cellSpan = cell.colSpan
// Check if our target position falls within this merged cell's span
if (cellIndex <= targetX && targetX < cellIndex + cellSpan) {
foundCell = cell
console.log("🎯 Found covering merged cell:", {
cellIndex,
cellSpan,
targetX,
covers: `${cellIndex} to ${cellIndex + cellSpan - 1}`
})
break
}
}
}
if (foundCell) {
targetCell = foundCell
console.log("✅ Using merged cell for rotation")
} else {
console.warn("❌ Could not find visible merged cell for position", targetX)
// Try to use the target cell anyway, even if hidden
console.log("🔄 Attempting to use hidden cell directly")
}
} else {
console.log("✅ Target cell is visible, using directly")
}
}
if (targetCell) {
const displayValue = value !== undefined && value !== null ? String(value).trim() : ''
console.log("Processing value:", displayValue, "for cell at position:", targetX)
if (displayValue) {
// Force clear any existing content first
targetCell.innerHTML = ''
// Apply rotation with improved styling
const rotatedDiv = document.createElement('div')
rotatedDiv.style.cssText = `
transform: rotate(-90deg) !important;
font-size: 12px !important;
height: 80px !important;
width: 20px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
white-space: nowrap !important;
margin: 0 auto !important;
transform-origin: center center !important;
position: relative !important;
color: #000 !important;
background: transparent !important;
`
rotatedDiv.textContent = displayValue
targetCell.appendChild(rotatedDiv)
console.log("✅ Rotation applied successfully to cell with value:", displayValue)
} else {
// Clear cell content but maintain structure
targetCell.innerHTML = ''
console.log("✅ Cleared cell content")
}
} else {
console.warn("❌ Target cell not found at index:", targetX + 1)
}
} else {
console.warn("❌ First row not found")
}
} else {
console.warn("❌ Table not found")
}
} catch (error) {
console.error(`Failed to merge ${colLetter}${row}:`, error)
console.error("❌ Error applying rotation:", error)
}
}
})
}
}
}
console.log("Config validation passed, creating jspreadsheet instance...")
console.log("Full config object:", JSON.stringify(config, null, 2))
console.log("Config keys:", Object.keys(config))
console.log("Data sample:", data.slice(0, 2))
console.log("Columns sample:", columns.slice(0, 3))
try {
jspreadsheetInstance.current = (jexcelLib as (el: HTMLElement, config: unknown) => unknown)(spreadsheetRef.current, config)
console.log("jspreadsheet initialized:", !!jspreadsheetInstance.current)
} catch (error) {
console.error("Error initializing jspreadsheet:", error)
console.error("Config that caused error:", JSON.stringify(config, null, 2))
console.error("Config keys that caused error:", Object.keys(config))
console.error("Data that caused error:", data?.slice(0, 2))
console.error("Columns that caused error:", columns?.slice(0, 3))
isInitializingRef.current = false
return
}
// Additional event listener for first row rotation as fallback
setTimeout(() => {
if (!isActiveRef.current || !spreadsheetRef.current) return
const table = spreadsheetRef.current?.querySelector('.jexcel tbody')
if (table) {
// Add input event listeners to first row cells
const firstRow = table.querySelector('tr:first-child')
if (firstRow) {
const cells = firstRow.querySelectorAll('td')
cells.forEach((cell, index) => {
if (index > 0) { // Skip row number cell
const cellElement = cell as HTMLElement
// Create rotation function for reuse
const applyRotation = (target: HTMLElement, value: string) => {
if (value.trim()) {
requestAnimationFrame(() => {
target.innerHTML = `<div style="
transform: rotate(-90deg) !important;
font-size: 12px !important;
height: 80px !important;
width: 20px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
white-space: nowrap !important;
margin: 0 auto !important;
transform-origin: center center !important;
position: relative !important;
color: #000 !important;
background: transparent !important;
">${value.trim()}</div>`
console.log("🎯 Direct rotation applied via event listener")
})
} else {
target.innerHTML = ''
}
}
// Listen for input events on the cell
cellElement.addEventListener('input', (e) => {
const target = e.target as HTMLElement
const value = target.textContent || target.innerText || ''
console.log("🎯 Direct input event on first row cell:", { index, value, colSpan: cellElement.colSpan })
applyRotation(target, value)
})
// Also listen for blur events
cellElement.addEventListener('blur', (e) => {
const target = e.target as HTMLElement
const value = target.textContent || target.innerText || ''
console.log("🎯 Blur event on first row cell:", { index, value, colSpan: cellElement.colSpan })
applyRotation(target, value)
})
// Listen for keyup events as well for immediate feedback
cellElement.addEventListener('keyup', (e) => {
const target = e.target as HTMLElement
const value = target.textContent || target.innerText || ''
console.log("🎯 Keyup event on first row cell:", { index, value, colSpan: cellElement.colSpan })
if (value.trim()) {
applyRotation(target, value)
}
})
}
})
}
}
}, 500)
// DISABLED: Mutation observer for first row rotation
// This was causing popup issues when switching tabs
// TODO: Implement a different approach for first row rotation if needed
// Apply cell merges for header rows after initialization - with improved error handling
setTimeout(() => {
if (!isActiveRef.current || !jspreadsheetInstance.current || !selectedMonth || !selectedYear) return
try {
const instance = jspreadsheetInstance.current as any
if (!instance.setMerge) return
console.log("Starting cell merging process...")
// Set merging flag to prevent onChange events during merge process
isMergingRef.current = true
// Clear any existing merges first to start fresh
if (instance.removeMerge && instance.getMerge) {
try {
const existingMerges = instance.getMerge()
if (existingMerges && Array.isArray(existingMerges)) {
existingMerges.forEach((merge: any) => {
try {
instance.removeMerge(merge.address)
} catch (e) {
// Ignore errors - merge might not exist
}
})
}
} catch (e) {
// Ignore errors getting existing merges
}
}
// Now apply new merges
const totalCols = data[0]?.length || 0
let mergeCount = 0
for (let row = 1; row <= 5; row++) {
for (let col = 1; col < totalCols; col += 2) {
// Double check we're still active
if (!isActiveRef.current || !jspreadsheetInstance.current) {
console.log("Component became inactive during merging")
isMergingRef.current = false
return
}
const colLetter = getExcelColumnName(col)
// Skip merging for BZ and CA columns
if (colLetter === 'BZ' || colLetter === 'CA') {
continue
}
try {
const cellAddress = `${colLetter}${row}`
console.log(`Attempting to merge: ${cellAddress}`)
instance.setMerge(cellAddress, 2, 1) // 2 columns, 1 row
mergeCount++
} catch (error) {
console.warn(`Failed to merge ${colLetter}${row}:`, error.message)
// Continue with other merges even if one fails
}
}
}
console.log(`Successfully applied ${mergeCount} cell merges`)
// Merge CA2 to CA6 (5 rows, 1 column)
try {
console.log("Attempting to merge CA2:CA6")
instance.setMerge("CA2", 1, 5) // 1 column, 5 rows (CA2, CA3, CA4, CA5, CA6)
console.log("Successfully merged CA2:CA6")
} catch (error) {
console.warn("Failed to merge CA2:CA6:", error.message)
}
// Clear merging flag after completion
isMergingRef.current = false
} catch (error) {
console.error("General error during cell merging:", error)
isMergingRef.current = false
}
}, 300) // Increased timeout to ensure spreadsheet is fully ready
// Clear initialization flag after successful setup - increased timeout to prevent rapid re-initializations
setTimeout(() => {
isInitializingRef.current = false
initTimeoutRef.current = null
console.log("Initialization completed, flag and timeout cleared")
}, 2000) // Extended to 2 seconds to ensure complete initialization
// Apply counter-clockwise rotation to data values only (exclude second column which contains field labels)
setTimeout(() => {
const table = spreadsheetRef.current?.querySelector('.jexcel tbody')
if (table) {
const rows = table.querySelectorAll('tr')
const totalCells = data[0]?.length || 0
// Rotate data values in rows 2, 3, 4, 5, 6 (day names, year, month, day, shifts) excluding first two columns
;[1, 2, 3, 4, 5].forEach(rowIndex => {
// Rotate data values in rows 1, 2, 3, 4, 5, 6 (first row, day names, year, month, day, shifts)
;[0, 1, 2, 3, 4, 5].forEach(rowIndex => {
if (rows[rowIndex]) {
const cells = rows[rowIndex].querySelectorAll('td')
cells.forEach((cell, cellIndex) => {
// Skip first two columns (row numbers and field labels)
if (cellIndex > 1) {
const originalText = cell.textContent
// Use 12px font for all rotated values (date values, day names, and shifts)
cell.innerHTML = `<div style="transform: rotate(-90deg); font-size: 12px; height: 20px; display: flex; align-items: center; justify-content: center; white-space: nowrap;">${originalText}</div>`
if (cellIndex > 1 && cellIndex < totalCells + 1) { // +1 because of row number column
const originalText = cell.textContent?.trim()
if (originalText) {
// Use 12px font for all rotated values (date values, day names, and shifts)
// For first row (rowIndex 0), ensure width: 100% for better text display
const extraStyle = rowIndex === 0 ? ' width: 100%;' : ''
cell.innerHTML = `<div style="transform: rotate(-90deg); font-size: 12px; height: 20px; display: flex; align-items: center; justify-content: center; white-space: nowrap;${extraStyle}">${originalText}</div>`
}
}
})
}
})
// Make only "Pohotovost TKB" bold, keep other field labels regular and ensure they're not rotated
;[0, 2, 3, 4, 5].forEach(rowIndex => {
;[0, 1, 2, 3, 4, 5].forEach(rowIndex => {
if (rows[rowIndex]) {
const cells = rows[rowIndex].querySelectorAll('td')
if (cells[1]) { // Second column (index 1)
@@ -353,20 +913,33 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
} else {
console.log("Cannot initialize - missing ref or jexcel library")
isInitializingRef.current = false
}
}
console.log("Calling loadJSpreadsheet...")
loadJSpreadsheet().catch(error => {
console.error("Error in loadJSpreadsheet:", error)
isInitializingRef.current = false
})
}, 100) // 100ms debounce delay
return () => {
// Clear timeout on cleanup
if (initTimeoutRef.current) {
clearTimeout(initTimeoutRef.current)
initTimeoutRef.current = null
}
isActiveRef.current = false
isMergingRef.current = false
isInitializingRef.current = false
if (jspreadsheetInstance.current) {
jspreadsheetInstance.current.destroy()
jspreadsheetInstance.current = null
}
}
}, [_teamId, selectedMonth, selectedYear, forceUpdate])
}, [teamId, selectedMonth, selectedYear, forceUpdate])
const handleSave = () => {
if (jspreadsheetInstance.current) {
@@ -400,11 +973,6 @@ export function TimeshiftSpreadsheet({ teamId: _teamId, teamName }: TimeshiftSpr
}
}
const handleAddEmployee = () => {
if (jspreadsheetInstance.current) {
jspreadsheetInstance.current.insertRow()
}
}
return (
<Card className="w-full">

44
ecosystem.config.js Normal file
View File

@@ -0,0 +1,44 @@
module.exports = {
apps: [
{
name: 'timeshift-auto-commit',
script: './watch-and-commit.js',
cwd: '/home/klas/timeshift',
watch: false, // We don't want PM2 to restart on file changes since we're watching files ourselves
autorestart: true,
max_restarts: 10,
min_uptime: '10s',
restart_delay: 5000,
env: {
NODE_ENV: 'development',
PWD: '/home/klas/timeshift'
},
log_file: '/home/klas/timeshift/logs/auto-commit.log',
out_file: '/home/klas/timeshift/logs/auto-commit.out.log',
error_file: '/home/klas/timeshift/logs/auto-commit.error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
max_memory_restart: '200M'
},
{
name: 'timeshift-dev',
script: 'npm',
args: 'run dev',
cwd: '/home/klas/timeshift',
watch: false,
autorestart: true,
max_restarts: 5,
min_uptime: '30s',
restart_delay: 10000,
env: {
NODE_ENV: 'development',
PORT: 3000
},
log_file: '/home/klas/timeshift/logs/dev-server.log',
out_file: '/home/klas/timeshift/logs/dev-server.out.log',
error_file: '/home/klas/timeshift/logs/dev-server.error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true
}
]
};

View File

@@ -0,0 +1,4 @@
2025-07-29 14:27:23 +02:00: (node:489145) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
2025-07-29 14:27:23 +02:00: (Use `node --trace-deprecation ...` to show where the warning was created)
2025-07-29 14:54:37 +02:00: (node:652376) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
2025-07-29 14:54:37 +02:00: (Use `node --trace-deprecation ...` to show where the warning was created)

304
logs/auto-commit.log Normal file
View File

@@ -0,0 +1,304 @@
2025-07-29 14:27:23 +02:00: 🚀 Timeshift Auto-Commit Watcher Started
2025-07-29 14:27:23 +02:00: ==========================================
2025-07-29 14:27:23 +02:00: 📅 Start time: 2025-07-29T12:27:23.269Z
2025-07-29 14:27:23 +02:00: 📁 Watching directories: components, app, lib, styles
2025-07-29 14:27:23 +02:00: 📄 File extensions: .tsx, .ts, .js, .jsx, .css, .scss, .json
2025-07-29 14:27:23 +02:00: ⏱️ Commit delay: 30s
2025-07-29 14:27:23 +02:00: 🚦 Max commits per hour: 10
2025-07-29 14:27:23 +02:00: 🔧 Process ID: 489145
2025-07-29 14:27:23 +02:00: ==========================================
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/components
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/app
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/lib
2025-07-29 14:27:23 +02:00: ⚠️ Directory not found: /home/klas/timeshift/styles
2025-07-29 14:27:23 +02:00: 🚀 Auto-commit system ready! Press Ctrl+C to stop.
2025-07-29 14:27:23 +02:00: 📋 Commands available:
2025-07-29 14:27:23 +02:00: ./auto-commit.sh commit [message]
2025-07-29 14:27:23 +02:00: ./auto-commit.sh restore-point [description]
2025-07-29 14:27:23 +02:00: ./auto-commit.sh list
2025-07-29 14:27:23 +02:00: ./auto-commit.sh cleanup
2025-07-29 14:27:23 +02:00: (node:489145) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
2025-07-29 14:27:23 +02:00: (Use `node --trace-deprecation ...` to show where the warning was created)
2025-07-29 14:27:28 +02:00: 🔖 Creating restore point...
2025-07-29 14:27:28 +02:00: ✅ Restore point created
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:31:08 +02:00: 🔄 Performing auto-commit...
2025-07-29 14:31:08 +02:00: ✅ Auto-commit successful
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:46 +02:00: 🔄 Performing auto-commit...
2025-07-29 14:35:46 +02:00: ✅ Auto-commit successful
2025-07-29 14:54:35 +02:00:
2025-07-29 14:54:35 +02:00: 🛑 Stopping auto-commit watcher...
2025-07-29 14:54:35 +02:00: 💾 Saving final changes...
2025-07-29 14:54:37 +02:00: 🚀 Timeshift Auto-Commit Watcher Started
2025-07-29 14:54:37 +02:00: ==========================================
2025-07-29 14:54:37 +02:00: 📅 Start time: 2025-07-29T12:54:37.822Z
2025-07-29 14:54:37 +02:00: 📁 Watching directories: components, app, lib, styles
2025-07-29 14:54:37 +02:00: 📄 File extensions: .tsx, .ts, .js, .jsx, .css, .scss, .json
2025-07-29 14:54:37 +02:00: ⏱️ Commit delay: 30s
2025-07-29 14:54:37 +02:00: 🚦 Max commits per hour: 10
2025-07-29 14:54:37 +02:00: 🔧 Process ID: 652376
2025-07-29 14:54:37 +02:00: ==========================================
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/components
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/app
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/lib
2025-07-29 14:54:37 +02:00: ⚠️ Directory not found: /home/klas/timeshift/styles
2025-07-29 14:54:37 +02:00: 🚀 Auto-commit system ready! Press Ctrl+C to stop.
2025-07-29 14:54:37 +02:00: 📋 Commands available:
2025-07-29 14:54:37 +02:00: ./auto-commit.sh commit [message]
2025-07-29 14:54:37 +02:00: ./auto-commit.sh restore-point [description]
2025-07-29 14:54:37 +02:00: ./auto-commit.sh list
2025-07-29 14:54:37 +02:00: ./auto-commit.sh cleanup
2025-07-29 14:54:37 +02:00: (node:652376) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
2025-07-29 14:54:37 +02:00: (Use `node --trace-deprecation ...` to show where the warning was created)
2025-07-29 14:54:42 +02:00: 🔖 Creating restore point...
2025-07-29 14:54:48 +02:00: ✅ Restore point created
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:45 +02:00: 🔄 Performing auto-commit...
2025-07-29 15:01:52 +02:00: ✅ Auto-commit successful
2025-07-29 15:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 15:24:39 +02:00: ✅ Restore point created
2025-07-29 15:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 15:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 15:54:39 +02:00: ✅ Restore point created
2025-07-29 16:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 16:24:39 +02:00: ✅ Restore point created
2025-07-29 16:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 16:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 16:54:39 +02:00: ✅ Restore point created
2025-07-29 17:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 17:24:40 +02:00: ✅ Restore point created
2025-07-29 17:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 17:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 17:54:40 +02:00: ✅ Restore point created
2025-07-29 18:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 18:24:39 +02:00: ✅ Restore point created
2025-07-29 18:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 18:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 18:54:39 +02:00: ✅ Restore point created
2025-07-29 19:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 19:24:39 +02:00: ✅ Restore point created
2025-07-29 19:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 19:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 19:54:39 +02:00: ✅ Restore point created
2025-07-29 20:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 20:24:41 +02:00: ✅ Restore point created
2025-07-29 20:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 20:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 20:54:41 +02:00: ✅ Restore point created
2025-07-29 21:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 21:24:40 +02:00: ✅ Restore point created
2025-07-29 21:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 21:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 21:54:40 +02:00: ✅ Restore point created
2025-07-29 22:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 22:24:40 +02:00: ✅ Restore point created
2025-07-29 22:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 22:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 22:54:40 +02:00: ✅ Restore point created
2025-07-29 23:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 23:24:40 +02:00: ✅ Restore point created
2025-07-29 23:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 23:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 23:54:40 +02:00: ✅ Restore point created
2025-07-30 00:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 00:24:40 +02:00: ✅ Restore point created
2025-07-30 00:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 00:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 00:54:41 +02:00: ✅ Restore point created
2025-07-30 01:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 01:24:41 +02:00: ✅ Restore point created
2025-07-30 01:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 01:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 01:54:40 +02:00: ✅ Restore point created
2025-07-30 02:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 02:24:42 +02:00: ✅ Restore point created
2025-07-30 02:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 02:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 02:54:44 +02:00: ✅ Restore point created
2025-07-30 03:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 03:24:41 +02:00: ✅ Restore point created
2025-07-30 03:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 03:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 03:54:41 +02:00: ✅ Restore point created
2025-07-30 04:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 04:24:48 +02:00: ✅ Restore point created
2025-07-30 04:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 04:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 04:54:41 +02:00: ✅ Restore point created
2025-07-30 05:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 05:25:01 +02:00: ✅ Restore point created
2025-07-30 05:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 05:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 05:54:42 +02:00: ✅ Restore point created
2025-07-30 06:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 06:24:42 +02:00: ✅ Restore point created
2025-07-30 06:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 06:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 06:54:42 +02:00: ✅ Restore point created
2025-07-30 07:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 07:24:44 +02:00: ✅ Restore point created
2025-07-30 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 07:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 07:54:43 +02:00: ✅ Restore point created
2025-07-30 08:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 08:24:45 +02:00: ✅ Restore point created
2025-07-30 08:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 08:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 08:54:46 +02:00: ✅ Restore point created
2025-07-30 09:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 09:24:50 +02:00: ✅ Restore point created
2025-07-30 09:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 09:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 09:56:10 +02:00: ✅ Restore point created
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:08:28 +02:00: 🔄 Performing auto-commit...
2025-07-30 10:08:37 +02:00: ✅ Auto-commit successful
2025-07-30 10:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 10:24:48 +02:00: ✅ Restore point created
2025-07-30 10:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 10:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 10:56:09 +02:00: ✅ Restore point created
2025-07-30 11:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 11:25:00 +02:00: ✅ Restore point created
2025-07-30 11:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 11:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 11:54:53 +02:00: ✅ Restore point created
2025-07-30 12:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 12:26:09 +02:00: ✅ Restore point created
2025-07-30 12:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 12:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 12:56:08 +02:00: ✅ Restore point created
2025-07-30 13:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 13:26:08 +02:00: ✅ Restore point created
2025-07-30 13:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 13:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 13:56:10 +02:00: ✅ Restore point created
2025-07-30 14:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 14:26:12 +02:00: ✅ Restore point created
2025-07-30 14:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 14:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 14:56:16 +02:00: ✅ Restore point created
2025-07-30 15:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 15:26:08 +02:00: ✅ Restore point created
2025-07-30 15:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 15:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 15:56:10 +02:00: ✅ Restore point created
2025-07-30 16:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 16:26:09 +02:00: ✅ Restore point created
2025-07-30 16:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 16:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 16:56:09 +02:00: ✅ Restore point created
2025-07-30 17:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 17:26:09 +02:00: ✅ Restore point created
2025-07-30 17:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 17:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 17:56:11 +02:00: ✅ Restore point created
2025-07-30 18:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 18:26:13 +02:00: ✅ Restore point created
2025-07-30 18:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 18:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 18:55:27 +02:00: ✅ Restore point created
2025-07-30 19:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 19:25:22 +02:00: ✅ Restore point created
2025-07-30 19:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 19:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 19:54:48 +02:00: ✅ Restore point created
2025-07-30 20:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 20:26:09 +02:00: ✅ Restore point created
2025-07-30 20:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 20:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 20:54:50 +02:00: ✅ Restore point created
2025-07-30 21:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 21:26:08 +02:00: ✅ Restore point created
2025-07-30 21:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 21:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 21:54:52 +02:00: ✅ Restore point created
2025-07-30 22:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 22:26:08 +02:00: ✅ Restore point created
2025-07-30 22:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 22:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 22:56:09 +02:00: ✅ Restore point created
2025-07-30 23:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 23:26:11 +02:00: ✅ Restore point created
2025-07-30 23:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 23:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 23:56:09 +02:00: ✅ Restore point created
2025-07-31 00:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 00:26:10 +02:00: ✅ Restore point created
2025-07-31 00:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 00:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 00:55:03 +02:00: ✅ Restore point created
2025-07-31 01:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 01:26:11 +02:00: ✅ Restore point created
2025-07-31 01:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 01:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 01:56:09 +02:00: ✅ Restore point created
2025-07-31 02:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 02:26:07 +02:00: ✅ Restore point created
2025-07-31 02:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 02:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 02:56:07 +02:00: ✅ Restore point created
2025-07-31 03:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 03:24:44 +02:00: ✅ Restore point created
2025-07-31 03:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 03:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 03:54:47 +02:00: ✅ Restore point created
2025-07-31 04:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 04:24:51 +02:00: ✅ Restore point created
2025-07-31 04:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 04:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 04:56:08 +02:00: ✅ Restore point created
2025-07-31 05:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 05:26:11 +02:00: ✅ Restore point created
2025-07-31 05:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 05:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 05:56:09 +02:00: ✅ Restore point created
2025-07-31 06:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 06:26:08 +02:00: ✅ Restore point created
2025-07-31 06:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 06:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 06:56:11 +02:00: ✅ Restore point created
2025-07-31 07:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 07:26:12 +02:00: ✅ Restore point created
2025-07-31 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 07:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 07:56:09 +02:00: ✅ Restore point created
2025-07-31 08:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 08:26:09 +02:00: ✅ Restore point created
2025-07-31 08:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 08:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 08:55:17 +02:00: ✅ Restore point created
2025-07-31 09:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 09:26:08 +02:00: ✅ Restore point created
2025-07-31 09:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 09:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 09:56:11 +02:00: ✅ Restore point created
2025-07-31 10:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 10:26:13 +02:00: ✅ Restore point created
2025-07-31 10:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 10:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 10:56:08 +02:00: ✅ Restore point created
2025-07-31 11:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 11:26:08 +02:00: ✅ Restore point created
2025-07-31 11:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 11:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 11:56:08 +02:00: ✅ Restore point created
2025-07-31 12:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 12:26:08 +02:00: ✅ Restore point created
2025-07-31 12:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 12:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 12:56:13 +02:00: ✅ Restore point created
2025-07-31 13:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 13:24:40 +02:00: ✅ Restore point created
2025-07-31 13:42:49 +02:00:
2025-07-31 13:42:49 +02:00: 🛑 Stopping auto-commit watcher...
2025-07-31 13:42:49 +02:00: 💾 Saving final changes...

300
logs/auto-commit.out.log Normal file
View File

@@ -0,0 +1,300 @@
2025-07-29 14:27:23 +02:00: 🚀 Timeshift Auto-Commit Watcher Started
2025-07-29 14:27:23 +02:00: ==========================================
2025-07-29 14:27:23 +02:00: 📅 Start time: 2025-07-29T12:27:23.269Z
2025-07-29 14:27:23 +02:00: 📁 Watching directories: components, app, lib, styles
2025-07-29 14:27:23 +02:00: 📄 File extensions: .tsx, .ts, .js, .jsx, .css, .scss, .json
2025-07-29 14:27:23 +02:00: ⏱️ Commit delay: 30s
2025-07-29 14:27:23 +02:00: 🚦 Max commits per hour: 10
2025-07-29 14:27:23 +02:00: 🔧 Process ID: 489145
2025-07-29 14:27:23 +02:00: ==========================================
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/components
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/app
2025-07-29 14:27:23 +02:00: 👀 Watching: /home/klas/timeshift/lib
2025-07-29 14:27:23 +02:00: ⚠️ Directory not found: /home/klas/timeshift/styles
2025-07-29 14:27:23 +02:00: 🚀 Auto-commit system ready! Press Ctrl+C to stop.
2025-07-29 14:27:23 +02:00: 📋 Commands available:
2025-07-29 14:27:23 +02:00: ./auto-commit.sh commit [message]
2025-07-29 14:27:23 +02:00: ./auto-commit.sh restore-point [description]
2025-07-29 14:27:23 +02:00: ./auto-commit.sh list
2025-07-29 14:27:23 +02:00: ./auto-commit.sh cleanup
2025-07-29 14:27:28 +02:00: 🔖 Creating restore point...
2025-07-29 14:27:28 +02:00: ✅ Restore point created
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:30:38 +02:00: 📝 File changed: components/test-component.tsx (change)
2025-07-29 14:31:08 +02:00: 🔄 Performing auto-commit...
2025-07-29 14:31:08 +02:00: ✅ Auto-commit successful
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:16 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 14:35:46 +02:00: 🔄 Performing auto-commit...
2025-07-29 14:35:46 +02:00: ✅ Auto-commit successful
2025-07-29 14:54:35 +02:00:
2025-07-29 14:54:35 +02:00: 🛑 Stopping auto-commit watcher...
2025-07-29 14:54:35 +02:00: 💾 Saving final changes...
2025-07-29 14:54:37 +02:00: 🚀 Timeshift Auto-Commit Watcher Started
2025-07-29 14:54:37 +02:00: ==========================================
2025-07-29 14:54:37 +02:00: 📅 Start time: 2025-07-29T12:54:37.822Z
2025-07-29 14:54:37 +02:00: 📁 Watching directories: components, app, lib, styles
2025-07-29 14:54:37 +02:00: 📄 File extensions: .tsx, .ts, .js, .jsx, .css, .scss, .json
2025-07-29 14:54:37 +02:00: ⏱️ Commit delay: 30s
2025-07-29 14:54:37 +02:00: 🚦 Max commits per hour: 10
2025-07-29 14:54:37 +02:00: 🔧 Process ID: 652376
2025-07-29 14:54:37 +02:00: ==========================================
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/components
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/app
2025-07-29 14:54:37 +02:00: 👀 Watching: /home/klas/timeshift/lib
2025-07-29 14:54:37 +02:00: ⚠️ Directory not found: /home/klas/timeshift/styles
2025-07-29 14:54:37 +02:00: 🚀 Auto-commit system ready! Press Ctrl+C to stop.
2025-07-29 14:54:37 +02:00: 📋 Commands available:
2025-07-29 14:54:37 +02:00: ./auto-commit.sh commit [message]
2025-07-29 14:54:37 +02:00: ./auto-commit.sh restore-point [description]
2025-07-29 14:54:37 +02:00: ./auto-commit.sh list
2025-07-29 14:54:37 +02:00: ./auto-commit.sh cleanup
2025-07-29 14:54:42 +02:00: 🔖 Creating restore point...
2025-07-29 14:54:48 +02:00: ✅ Restore point created
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:15 +02:00: 📝 File changed: components/timeshift-spreadsheet.tsx (change)
2025-07-29 15:01:45 +02:00: 🔄 Performing auto-commit...
2025-07-29 15:01:52 +02:00: ✅ Auto-commit successful
2025-07-29 15:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 15:24:39 +02:00: ✅ Restore point created
2025-07-29 15:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 15:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 15:54:39 +02:00: ✅ Restore point created
2025-07-29 16:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 16:24:39 +02:00: ✅ Restore point created
2025-07-29 16:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 16:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 16:54:39 +02:00: ✅ Restore point created
2025-07-29 17:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 17:24:40 +02:00: ✅ Restore point created
2025-07-29 17:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 17:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 17:54:40 +02:00: ✅ Restore point created
2025-07-29 18:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 18:24:39 +02:00: ✅ Restore point created
2025-07-29 18:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 18:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 18:54:39 +02:00: ✅ Restore point created
2025-07-29 19:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 19:24:39 +02:00: ✅ Restore point created
2025-07-29 19:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 19:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 19:54:39 +02:00: ✅ Restore point created
2025-07-29 20:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 20:24:41 +02:00: ✅ Restore point created
2025-07-29 20:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 20:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 20:54:41 +02:00: ✅ Restore point created
2025-07-29 21:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 21:24:40 +02:00: ✅ Restore point created
2025-07-29 21:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 21:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 21:54:40 +02:00: ✅ Restore point created
2025-07-29 22:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 22:24:40 +02:00: ✅ Restore point created
2025-07-29 22:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 22:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 22:54:40 +02:00: ✅ Restore point created
2025-07-29 23:24:37 +02:00: 🔖 Creating restore point...
2025-07-29 23:24:40 +02:00: ✅ Restore point created
2025-07-29 23:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-29 23:54:37 +02:00: 🔖 Creating restore point...
2025-07-29 23:54:40 +02:00: ✅ Restore point created
2025-07-30 00:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 00:24:40 +02:00: ✅ Restore point created
2025-07-30 00:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 00:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 00:54:41 +02:00: ✅ Restore point created
2025-07-30 01:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 01:24:41 +02:00: ✅ Restore point created
2025-07-30 01:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 01:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 01:54:40 +02:00: ✅ Restore point created
2025-07-30 02:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 02:24:42 +02:00: ✅ Restore point created
2025-07-30 02:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 02:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 02:54:44 +02:00: ✅ Restore point created
2025-07-30 03:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 03:24:41 +02:00: ✅ Restore point created
2025-07-30 03:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 03:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 03:54:41 +02:00: ✅ Restore point created
2025-07-30 04:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 04:24:48 +02:00: ✅ Restore point created
2025-07-30 04:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 04:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 04:54:41 +02:00: ✅ Restore point created
2025-07-30 05:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 05:25:01 +02:00: ✅ Restore point created
2025-07-30 05:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 05:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 05:54:42 +02:00: ✅ Restore point created
2025-07-30 06:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 06:24:42 +02:00: ✅ Restore point created
2025-07-30 06:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 06:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 06:54:42 +02:00: ✅ Restore point created
2025-07-30 07:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 07:24:44 +02:00: ✅ Restore point created
2025-07-30 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 07:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 07:54:43 +02:00: ✅ Restore point created
2025-07-30 08:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 08:24:45 +02:00: ✅ Restore point created
2025-07-30 08:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 08:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 08:54:46 +02:00: ✅ Restore point created
2025-07-30 09:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 09:24:50 +02:00: ✅ Restore point created
2025-07-30 09:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 09:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 09:56:10 +02:00: ✅ Restore point created
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:07:58 +02:00: 📝 File changed: app/layout.tsx (change)
2025-07-30 10:08:28 +02:00: 🔄 Performing auto-commit...
2025-07-30 10:08:37 +02:00: ✅ Auto-commit successful
2025-07-30 10:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 10:24:48 +02:00: ✅ Restore point created
2025-07-30 10:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 10:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 10:56:09 +02:00: ✅ Restore point created
2025-07-30 11:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 11:25:00 +02:00: ✅ Restore point created
2025-07-30 11:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 11:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 11:54:53 +02:00: ✅ Restore point created
2025-07-30 12:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 12:26:09 +02:00: ✅ Restore point created
2025-07-30 12:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 12:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 12:56:08 +02:00: ✅ Restore point created
2025-07-30 13:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 13:26:08 +02:00: ✅ Restore point created
2025-07-30 13:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 13:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 13:56:10 +02:00: ✅ Restore point created
2025-07-30 14:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 14:26:12 +02:00: ✅ Restore point created
2025-07-30 14:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 14:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 14:56:16 +02:00: ✅ Restore point created
2025-07-30 15:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 15:26:08 +02:00: ✅ Restore point created
2025-07-30 15:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 15:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 15:56:10 +02:00: ✅ Restore point created
2025-07-30 16:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 16:26:09 +02:00: ✅ Restore point created
2025-07-30 16:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 16:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 16:56:09 +02:00: ✅ Restore point created
2025-07-30 17:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 17:26:09 +02:00: ✅ Restore point created
2025-07-30 17:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 17:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 17:56:11 +02:00: ✅ Restore point created
2025-07-30 18:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 18:26:13 +02:00: ✅ Restore point created
2025-07-30 18:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 18:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 18:55:27 +02:00: ✅ Restore point created
2025-07-30 19:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 19:25:22 +02:00: ✅ Restore point created
2025-07-30 19:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 19:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 19:54:48 +02:00: ✅ Restore point created
2025-07-30 20:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 20:26:09 +02:00: ✅ Restore point created
2025-07-30 20:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 20:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 20:54:50 +02:00: ✅ Restore point created
2025-07-30 21:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 21:26:08 +02:00: ✅ Restore point created
2025-07-30 21:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 21:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 21:54:52 +02:00: ✅ Restore point created
2025-07-30 22:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 22:26:08 +02:00: ✅ Restore point created
2025-07-30 22:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 22:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 22:56:09 +02:00: ✅ Restore point created
2025-07-30 23:24:37 +02:00: 🔖 Creating restore point...
2025-07-30 23:26:11 +02:00: ✅ Restore point created
2025-07-30 23:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-30 23:54:37 +02:00: 🔖 Creating restore point...
2025-07-30 23:56:09 +02:00: ✅ Restore point created
2025-07-31 00:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 00:26:10 +02:00: ✅ Restore point created
2025-07-31 00:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 00:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 00:55:03 +02:00: ✅ Restore point created
2025-07-31 01:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 01:26:11 +02:00: ✅ Restore point created
2025-07-31 01:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 01:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 01:56:09 +02:00: ✅ Restore point created
2025-07-31 02:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 02:26:07 +02:00: ✅ Restore point created
2025-07-31 02:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 02:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 02:56:07 +02:00: ✅ Restore point created
2025-07-31 03:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 03:24:44 +02:00: ✅ Restore point created
2025-07-31 03:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 03:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 03:54:47 +02:00: ✅ Restore point created
2025-07-31 04:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 04:24:51 +02:00: ✅ Restore point created
2025-07-31 04:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 04:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 04:56:08 +02:00: ✅ Restore point created
2025-07-31 05:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 05:26:11 +02:00: ✅ Restore point created
2025-07-31 05:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 05:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 05:56:09 +02:00: ✅ Restore point created
2025-07-31 06:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 06:26:08 +02:00: ✅ Restore point created
2025-07-31 06:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 06:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 06:56:11 +02:00: ✅ Restore point created
2025-07-31 07:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 07:26:12 +02:00: ✅ Restore point created
2025-07-31 07:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 07:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 07:56:09 +02:00: ✅ Restore point created
2025-07-31 08:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 08:26:09 +02:00: ✅ Restore point created
2025-07-31 08:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 08:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 08:55:17 +02:00: ✅ Restore point created
2025-07-31 09:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 09:26:08 +02:00: ✅ Restore point created
2025-07-31 09:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 09:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 09:56:11 +02:00: ✅ Restore point created
2025-07-31 10:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 10:26:13 +02:00: ✅ Restore point created
2025-07-31 10:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 10:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 10:56:08 +02:00: ✅ Restore point created
2025-07-31 11:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 11:26:08 +02:00: ✅ Restore point created
2025-07-31 11:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 11:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 11:56:08 +02:00: ✅ Restore point created
2025-07-31 12:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 12:26:08 +02:00: ✅ Restore point created
2025-07-31 12:54:37 +02:00: 🔄 Hourly reset: Commit counter reset to 0
2025-07-31 12:54:37 +02:00: 🔖 Creating restore point...
2025-07-31 12:56:13 +02:00: ✅ Restore point created
2025-07-31 13:24:37 +02:00: 🔖 Creating restore point...
2025-07-31 13:24:40 +02:00: ✅ Restore point created
2025-07-31 13:42:49 +02:00:
2025-07-31 13:42:49 +02:00: 🛑 Stopping auto-commit watcher...
2025-07-31 13:42:49 +02:00: 💾 Saving final changes...

View File

@@ -4,9 +4,23 @@
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"auto-commit": "./auto-commit.sh",
"watch-commit": "node watch-and-commit.js",
"save": "./auto-commit.sh commit",
"restore-point": "./auto-commit.sh restore-point",
"pm2:start": "pm2 start ecosystem.config.js",
"pm2:stop": "pm2 stop ecosystem.config.js",
"pm2:restart": "pm2 restart ecosystem.config.js",
"pm2:delete": "pm2 delete ecosystem.config.js",
"pm2:logs": "pm2 logs timeshift-auto-commit",
"pm2:status": "pm2 status",
"pm2:monit": "pm2 monit",
"services:start": "pm2 start ecosystem.config.js --only timeshift-auto-commit",
"services:stop": "pm2 stop timeshift-auto-commit",
"services:logs": "pm2 logs timeshift-auto-commit --lines 50"
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.14",

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

103
start-services.sh Executable file
View File

@@ -0,0 +1,103 @@
#!/bin/bash
# Timeshift Project Services Startup Script
# This script starts the auto-commit watcher and development server using PM2
set -e
echo "🚀 Starting Timeshift Project Services"
echo "========================================"
# Function to check if PM2 is installed
check_pm2() {
if ! command -v pm2 &> /dev/null; then
echo "❌ PM2 is not installed. Please install it first:"
echo " npm install -g pm2"
exit 1
fi
echo "✅ PM2 is available"
}
# Function to start services
start_services() {
echo ""
echo "🔧 Starting services..."
# Stop any existing services first
pm2 delete timeshift-auto-commit 2>/dev/null || true
pm2 delete timeshift-dev 2>/dev/null || true
# Start the auto-commit watcher
echo "📁 Starting auto-commit watcher..."
pm2 start ecosystem.config.js --only timeshift-auto-commit
# Wait a moment for the service to start
sleep 2
echo ""
echo "✅ Services started successfully!"
echo ""
# Show status
pm2 status
echo ""
echo "📋 Service Management Commands:"
echo " npm run services:logs - View auto-commit logs"
echo " npm run services:stop - Stop auto-commit service"
echo " npm run pm2:status - Check all PM2 services"
echo " npm run pm2:monit - Open PM2 monitoring"
echo ""
echo "🌐 Development Server:"
echo " npm run dev - Start Next.js dev server manually"
echo " npm run pm2:start - Start both services with PM2"
echo ""
echo "💾 Manual Save Commands:"
echo " npm run save - Save changes immediately"
echo " npm run restore-point - Create a restore point"
echo ""
}
# Function to show logs
show_logs() {
echo "📋 Auto-commit service logs (last 20 lines):"
echo "============================================"
pm2 logs timeshift-auto-commit --lines 20 --nostream
}
# Main execution
case "$1" in
"logs")
show_logs
;;
"stop")
echo "🛑 Stopping auto-commit service..."
pm2 stop timeshift-auto-commit
echo "✅ Service stopped"
;;
"restart")
echo "🔄 Restarting auto-commit service..."
pm2 restart timeshift-auto-commit
echo "✅ Service restarted"
;;
"status")
pm2 status
;;
*)
check_pm2
start_services
# Option to show logs
echo "👀 Would you like to see the logs? (y/n)"
read -t 10 -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
show_logs
fi
;;
esac
echo ""
echo "🎯 Auto-commit watcher is now running in the background!"
echo "🔄 Your changes will be automatically saved every 30 seconds."
echo "🛡️ No more lost work when Claude restarts!"

2
test-auto-commit.txt Normal file
View File

@@ -0,0 +1,2 @@
This is a test file to verify auto-commit is working.
Created at: 2025-07-29 14:27:30

189
watch-and-commit.js Executable file
View File

@@ -0,0 +1,189 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
// Configuration
const WATCH_DIRS = ['components', 'app', 'lib', 'styles'];
const WATCH_EXTENSIONS = ['.tsx', '.ts', '.js', '.jsx', '.css', '.scss', '.json'];
const COMMIT_DELAY = 30000; // 30 seconds delay before auto-commit
const MAX_COMMITS_PER_HOUR = 10;
class AutoCommitWatcher {
constructor() {
this.commitQueue = new Set();
this.commitTimeout = null;
this.commitsThisHour = 0;
this.lastCommitTime = 0;
this.startTime = new Date();
// Reset commit counter every hour
setInterval(() => {
this.commitsThisHour = 0;
console.log('🔄 Hourly reset: Commit counter reset to 0');
}, 3600000);
// Log startup info
console.log('🚀 Timeshift Auto-Commit Watcher Started');
console.log('==========================================');
console.log(`📅 Start time: ${this.startTime.toISOString()}`);
console.log(`📁 Watching directories: ${WATCH_DIRS.join(', ')}`);
console.log(`📄 File extensions: ${WATCH_EXTENSIONS.join(', ')}`);
console.log(`⏱️ Commit delay: ${COMMIT_DELAY/1000}s`);
console.log(`🚦 Max commits per hour: ${MAX_COMMITS_PER_HOUR}`);
console.log(`🔧 Process ID: ${process.pid}`);
console.log('==========================================');
}
start() {
WATCH_DIRS.forEach(dir => {
const fullPath = path.join(process.cwd(), dir);
if (fs.existsSync(fullPath)) {
this.watchDirectory(fullPath);
console.log(`👀 Watching: ${fullPath}`);
} else {
console.log(`⚠️ Directory not found: ${fullPath}`);
}
});
}
watchDirectory(dirPath) {
try {
fs.watch(dirPath, { recursive: true }, (eventType, filename) => {
if (!filename) return;
const filePath = path.join(dirPath, filename);
const ext = path.extname(filename);
// Check if file extension is in our watch list
if (WATCH_EXTENSIONS.includes(ext)) {
this.handleFileChange(filePath, eventType);
}
});
} catch (error) {
console.error(`❌ Error watching directory ${dirPath}:`, error.message);
}
}
handleFileChange(filePath, eventType) {
const relativePath = path.relative(process.cwd(), filePath);
console.log(`📝 File changed: ${relativePath} (${eventType})`);
// Add to commit queue
this.commitQueue.add(relativePath);
// Clear existing timeout and set new one
if (this.commitTimeout) {
clearTimeout(this.commitTimeout);
}
this.commitTimeout = setTimeout(() => {
this.performAutoCommit();
}, COMMIT_DELAY);
}
async performAutoCommit() {
// Rate limiting
if (this.commitsThisHour >= MAX_COMMITS_PER_HOUR) {
console.log(`⏸️ Rate limit reached (${MAX_COMMITS_PER_HOUR} commits/hour). Skipping auto-commit.`);
this.commitQueue.clear();
return;
}
// Check if enough time has passed since last commit
const now = Date.now();
if (now - this.lastCommitTime < COMMIT_DELAY) {
console.log('⏸️ Too soon since last commit. Skipping.');
return;
}
if (this.commitQueue.size === 0) {
console.log('📋 No files in commit queue');
return;
}
try {
// Check if there are actually changes to commit
const { stdout: status } = await execAsync('git status --porcelain');
if (!status.trim()) {
console.log('📝 No actual changes to commit');
this.commitQueue.clear();
return;
}
console.log('🔄 Performing auto-commit...');
// Create commit message with changed files
const changedFiles = Array.from(this.commitQueue).slice(0, 5); // Limit to 5 files in message
const fileList = changedFiles.join(', ');
const moreFiles = this.commitQueue.size > 5 ? ` and ${this.commitQueue.size - 5} more` : '';
const message = `Auto-save: Updated ${fileList}${moreFiles}`;
// Use our auto-commit script
await execAsync(`./auto-commit.sh commit "${message}"`);
console.log('✅ Auto-commit successful');
this.commitsThisHour++;
this.lastCommitTime = now;
this.commitQueue.clear();
} catch (error) {
console.error('❌ Auto-commit failed:', error.message);
}
}
async createRestorePoint(description = 'Auto restore point') {
try {
console.log('🔖 Creating restore point...');
await execAsync(`./auto-commit.sh restore-point "${description}"`);
console.log('✅ Restore point created');
} catch (error) {
console.error('❌ Failed to create restore point:', error.message);
}
}
}
// Handle process termination gracefully
process.on('SIGINT', async () => {
console.log('\n🛑 Stopping auto-commit watcher...');
// Perform final commit if there are pending changes
try {
const { stdout: status } = await execAsync('git status --porcelain');
if (status.trim()) {
console.log('💾 Saving final changes...');
await execAsync('./auto-commit.sh commit "Final auto-save before shutdown"');
}
} catch (error) {
console.error('❌ Error during shutdown save:', error.message);
}
console.log('👋 Auto-commit watcher stopped');
process.exit(0);
});
// Start the watcher
const watcher = new AutoCommitWatcher();
watcher.start();
// Create restore point on startup
setTimeout(() => {
watcher.createRestorePoint('Session start');
}, 5000);
// Create periodic restore points (every 30 minutes)
setInterval(() => {
watcher.createRestorePoint('Periodic backup');
}, 30 * 60 * 1000);
console.log('🚀 Auto-commit system ready! Press Ctrl+C to stop.');
console.log('📋 Commands available:');
console.log(' ./auto-commit.sh commit [message]');
console.log(' ./auto-commit.sh restore-point [description]');
console.log(' ./auto-commit.sh list');
console.log(' ./auto-commit.sh cleanup');