iobroker.time-tracker 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +386 -0
- package/admin/i18n/de.json +34 -0
- package/admin/i18n/en.json +1 -0
- package/admin/i18n/es.json +34 -0
- package/admin/i18n/fr.json +34 -0
- package/admin/i18n/it.json +34 -0
- package/admin/i18n/nl.json +34 -0
- package/admin/i18n/pl.json +34 -0
- package/admin/i18n/pt.json +34 -0
- package/admin/i18n/ru.json +34 -0
- package/admin/i18n/uk.json +34 -0
- package/admin/i18n/zh-cn.json +34 -0
- package/admin/jsonConfig.json +266 -0
- package/admin/time-tracker.png +0 -0
- package/build/lib/adapter/automation.js +100 -0
- package/build/lib/adapter/automation.js.map +7 -0
- package/build/lib/adapter/commands.js +160 -0
- package/build/lib/adapter/commands.js.map +7 -0
- package/build/lib/adapter/messages.js +207 -0
- package/build/lib/adapter/messages.js.map +7 -0
- package/build/lib/adapter/presence.js +129 -0
- package/build/lib/adapter/presence.js.map +7 -0
- package/build/lib/adapter/states.js +330 -0
- package/build/lib/adapter/states.js.map +7 -0
- package/build/lib/adapter/triggers.js +92 -0
- package/build/lib/adapter/triggers.js.map +7 -0
- package/build/lib/db/database.js +96 -0
- package/build/lib/db/database.js.map +7 -0
- package/build/lib/db/migrations.js +603 -0
- package/build/lib/db/migrations.js.map +7 -0
- package/build/lib/db/repositories/absences.js +432 -0
- package/build/lib/db/repositories/absences.js.map +7 -0
- package/build/lib/db/repositories/audit.js +90 -0
- package/build/lib/db/repositories/audit.js.map +7 -0
- package/build/lib/db/repositories/automations.js +326 -0
- package/build/lib/db/repositories/automations.js.map +7 -0
- package/build/lib/db/repositories/entries.js +335 -0
- package/build/lib/db/repositories/entries.js.map +7 -0
- package/build/lib/db/repositories/holidays.js +156 -0
- package/build/lib/db/repositories/holidays.js.map +7 -0
- package/build/lib/db/repositories/payouts.js +221 -0
- package/build/lib/db/repositories/payouts.js.map +7 -0
- package/build/lib/db/repositories/rfid.js +264 -0
- package/build/lib/db/repositories/rfid.js.map +7 -0
- package/build/lib/db/repositories/rules.js +356 -0
- package/build/lib/db/repositories/rules.js.map +7 -0
- package/build/lib/db/repositories/settings.js +91 -0
- package/build/lib/db/repositories/settings.js.map +7 -0
- package/build/lib/db/repositories/terminals.js +243 -0
- package/build/lib/db/repositories/terminals.js.map +7 -0
- package/build/lib/db/repositories/triggers.js +240 -0
- package/build/lib/db/repositories/triggers.js.map +7 -0
- package/build/lib/db/repositories/users.js +491 -0
- package/build/lib/db/repositories/users.js.map +7 -0
- package/build/lib/db/seed.js +180 -0
- package/build/lib/db/seed.js.map +7 -0
- package/build/lib/domain/avatar.js +63 -0
- package/build/lib/domain/avatar.js.map +7 -0
- package/build/lib/domain/breaks.js +70 -0
- package/build/lib/domain/breaks.js.map +7 -0
- package/build/lib/domain/calculation.js +150 -0
- package/build/lib/domain/calculation.js.map +7 -0
- package/build/lib/domain/holidays.js +113 -0
- package/build/lib/domain/holidays.js.map +7 -0
- package/build/lib/domain/punch.js +99 -0
- package/build/lib/domain/punch.js.map +7 -0
- package/build/lib/domain/target.js +89 -0
- package/build/lib/domain/target.js.map +7 -0
- package/build/lib/errors.js +56 -0
- package/build/lib/errors.js.map +7 -0
- package/build/lib/reports/labels.js +358 -0
- package/build/lib/reports/labels.js.map +7 -0
- package/build/lib/reports/pdf.js +308 -0
- package/build/lib/reports/pdf.js.map +7 -0
- package/build/lib/reports/types.js +32 -0
- package/build/lib/reports/types.js.map +7 -0
- package/build/lib/reports/xls.js +211 -0
- package/build/lib/reports/xls.js.map +7 -0
- package/build/lib/services/aggregation.js +495 -0
- package/build/lib/services/aggregation.js.map +7 -0
- package/build/lib/services/auth.js +381 -0
- package/build/lib/services/auth.js.map +7 -0
- package/build/lib/services/backup.js +372 -0
- package/build/lib/services/backup.js.map +7 -0
- package/build/lib/services/closing.js +106 -0
- package/build/lib/services/closing.js.map +7 -0
- package/build/lib/services/sessionSecret.js +100 -0
- package/build/lib/services/sessionSecret.js.map +7 -0
- package/build/lib/services/sync.js +278 -0
- package/build/lib/services/sync.js.map +7 -0
- package/build/lib/util/time.js +125 -0
- package/build/lib/util/time.js.map +7 -0
- package/build/lib/web/api.js +2589 -0
- package/build/lib/web/api.js.map +7 -0
- package/build/lib/web/cookies.js +80 -0
- package/build/lib/web/cookies.js.map +7 -0
- package/build/lib/web/events.js +50 -0
- package/build/lib/web/events.js.map +7 -0
- package/build/lib/web/pin-guard.js +86 -0
- package/build/lib/web/pin-guard.js.map +7 -0
- package/build/lib/web/problem.js +129 -0
- package/build/lib/web/problem.js.map +7 -0
- package/build/lib/web/rate-limit.js +65 -0
- package/build/lib/web/rate-limit.js.map +7 -0
- package/build/lib/web/router.js +274 -0
- package/build/lib/web/router.js.map +7 -0
- package/build/lib/web/server.js +189 -0
- package/build/lib/web/server.js.map +7 -0
- package/build/lib/web/static.js +151 -0
- package/build/lib/web/static.js.map +7 -0
- package/build/lib/web/stream.js +135 -0
- package/build/lib/web/stream.js.map +7 -0
- package/build/main.js +986 -0
- package/build/main.js.map +7 -0
- package/io-package.json +221 -0
- package/package.json +131 -0
- package/src-pwa/src/i18n/de.json +359 -0
- package/src-pwa/src/i18n/en.json +359 -0
- package/src-pwa/src/i18n/es.json +359 -0
- package/src-pwa/src/i18n/fr.json +359 -0
- package/src-pwa/src/i18n/index.ts +96 -0
- package/src-pwa/src/i18n/it.json +359 -0
- package/src-pwa/src/i18n/nl.json +359 -0
- package/src-pwa/src/i18n/pl.json +359 -0
- package/src-pwa/src/i18n/pt.json +359 -0
- package/src-pwa/src/i18n/ru.json +359 -0
- package/src-pwa/src/i18n/uk.json +359 -0
- package/src-pwa/src/i18n/zh-cn.json +359 -0
- package/www/assets/index-QI3wrEvW.js +119 -0
- package/www/assets/index-QI3wrEvW.js.map +1 -0
- package/www/assets/workbox-window.prod.es5-Bd17z0YL.js +3 -0
- package/www/assets/workbox-window.prod.es5-Bd17z0YL.js.map +1 -0
- package/www/favicon.svg +16 -0
- package/www/icon-192.png +0 -0
- package/www/icon-512.png +0 -0
- package/www/index.html +38 -0
- package/www/manifest.webmanifest +1 -0
- package/www/person.png +0 -0
- package/www/sw.js +3 -0
- package/www/sw.js.map +1 -0
- package/www/workbox-9c191d2f.js +3 -0
- package/www/workbox-9c191d2f.js.map +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Eerste start: de eerste beheerder wordt bij de eerste start van de instantie aangemaakt. Blijft het wachtwoordveld leeg, dan wordt het gegenereerde wachtwoord ÉÉN keer in het ioBroker-log geschreven (open links “Logs” en zoek de gele regel met “created with the start password”) — beide velden staan op het tabblad “Migratie en back-up”. De app vraagt bij de eerste aanmelding om een nieuw wachtwoord.</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Het account van de eerste beheerder wordt bij de allereerste start aangemaakt. Blijft het wachtwoordveld hieronder leeg, dan maakt de adapter een willekeurig wachtwoord en schrijft het ÉÉN keer in het ioBroker-log: open links in de ioBroker-admin “Logs” en zoek de gele regel met “created with the start password” — dat is het wachtwoord voor de eerste aanmelding. De app vraagt daarna direct om een nieuw wachtwoord. Vul hieronder liever meteen je eigen wachtwoord in als je dat wilt overslaan.</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = alleen deze computer",
|
|
5
|
+
"Badge link secret (HMAC)": "Badgelinkgeheim (HMAC)",
|
|
6
|
+
"Bind address": "Bindadres",
|
|
7
|
+
"Calculate absences only until today": "Bereken de afwezigheden tot en met vandaag",
|
|
8
|
+
"Database file (empty = adapter data directory)": "Databasebestand (leeg = adaptergegevensmap)",
|
|
9
|
+
"Days users may edit on their own": "Dagen waarop gebruikers zelf kunnen bewerken",
|
|
10
|
+
"Default language for new users": "Standaardtaal voor nieuwe gebruikers",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "leeg = er wordt eenmalig een willekeurig wachtwoord in het adapterlog geschreven; het moet bij de eerste aanmelding worden gewijzigd",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "leeg = de adapter genereert er eenmalig een en bewaart het naast de database, zodat sessies herstarts overleven",
|
|
13
|
+
"Enable kiosk terminal": "Schakel kioskterminal in",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "Eerste start: het startwachtwoord staat in het ioBroker-log",
|
|
15
|
+
"General": "Algemeen",
|
|
16
|
+
"Holiday country": "Land voor feestdagen",
|
|
17
|
+
"Instance time zone": "Tijdzone van instantie",
|
|
18
|
+
"Keep database backups for days": "Bewaar databaseback-ups voor een aantal dagen",
|
|
19
|
+
"Login of the first administrator": "Login van de eerste beheerder",
|
|
20
|
+
"Migration and backup": "Migratie en back-up",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "alleen inschakelen als er een reverse proxy voor de adapter staat",
|
|
22
|
+
"Port": "Poort",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "Snel klokken afronden op minuten (0 = uit)",
|
|
24
|
+
"Security": "Beveiliging",
|
|
25
|
+
"Session lifetime in minutes": "Sessielevensduur in minuten",
|
|
26
|
+
"Session secret": "Sessiegeheim",
|
|
27
|
+
"Start password of the first administrator": "Startwachtwoord van de eerste beheerder",
|
|
28
|
+
"Subtract working time from absences": "Trek de werktijd af van de afwezigheden",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "de poort van de webapp, de API en de terminal; 8082 blijft vrij voor vis en web",
|
|
30
|
+
"Time rules": "Tijdregels",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "Reverse proxy vertrouwen (X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "eenmalig gebruikt: het account wordt aangemaakt wanneer de instantie nog geen beheerder heeft",
|
|
33
|
+
"time-tracker adapter settings": "Adapterinstellingen voor time-tracker"
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Pierwsze uruchomienie: pierwszy administrator powstaje przy pierwszym uruchomieniu instancji. Jeśli pole hasła pozostanie puste, wygenerowane hasło zostanie zapisane RAZ w logu ioBroker (otwórz „Logs” po lewej i znajdź żółtą linię z „created with the start password”) — oba pola są na karcie „Migracja i kopia zapasowa”. Aplikacja poprosi o nowe hasło przy pierwszym logowaniu.</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Konto pierwszego administratora powstaje przy pierwszym uruchomieniu. Jeśli pole hasła poniżej pozostanie puste, adapter wygeneruje losowe hasło i zapisze je RAZ w logu ioBroker: otwórz „Logs” po lewej w adminie ioBroker i znajdź żółtą linię z „created with the start password” — to hasło do pierwszego logowania. Aplikacja od razu poprosi o nowe hasło. Jeśli chcesz to pominąć, wpisz poniżej własne hasło.</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = tylko ten komputer",
|
|
5
|
+
"Badge link secret (HMAC)": "Tajny link do plakietki (HMAC)",
|
|
6
|
+
"Bind address": "Adres powiązania",
|
|
7
|
+
"Calculate absences only until today": "Oblicz nieobecności tylko do dzisiaj",
|
|
8
|
+
"Database file (empty = adapter data directory)": "Plik bazy danych (pusty = katalog danych adaptera)",
|
|
9
|
+
"Days users may edit on their own": "Dni, które użytkownicy mogą edytować samodzielnie",
|
|
10
|
+
"Default language for new users": "Domyślny język dla nowych użytkowników",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "puste = losowe hasło zostanie jednorazowo zapisane w dzienniku adaptera; należy je zmienić przy pierwszym logowaniu",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "puste = adapter wygeneruje raz wartość i zapisze ją obok bazy danych, aby sesje przetrwały restarty",
|
|
13
|
+
"Enable kiosk terminal": "Włącz terminal kiosku",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "Pierwsze uruchomienie: hasło startowe jest w logu ioBroker",
|
|
15
|
+
"General": "Ogólny",
|
|
16
|
+
"Holiday country": "Kraj świąt",
|
|
17
|
+
"Instance time zone": "Strefa czasowa instancji",
|
|
18
|
+
"Keep database backups for days": "Przechowuj kopie zapasowe bazy danych przez kilka dni",
|
|
19
|
+
"Login of the first administrator": "Login pierwszego administratora",
|
|
20
|
+
"Migration and backup": "Migracja i kopia zapasowa",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "włączać tylko, gdy przed adapterem stoi odwrotne proxy",
|
|
22
|
+
"Port": "Port",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "Zaokrąglij szybkie stemple do minut (0 = wyłączone)",
|
|
24
|
+
"Security": "Bezpieczeństwo",
|
|
25
|
+
"Session lifetime in minutes": "Czas życia sesji w minutach",
|
|
26
|
+
"Session secret": "Sekret sesji",
|
|
27
|
+
"Start password of the first administrator": "Hasło startowe pierwszego administratora",
|
|
28
|
+
"Subtract working time from absences": "Odejmij czas pracy od nieobecności",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "port aplikacji internetowej, API i terminala; 8082 pozostaje wolny dla vis i web",
|
|
30
|
+
"Time rules": "Zasady czasu pracy",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "Ufaj odwrotnemu proxy (X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "używane jednorazowo: konto powstaje, gdy instancja nie ma jeszcze administratora",
|
|
33
|
+
"time-tracker adapter settings": "Ustawienia adaptera dla time-tracker"
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Primeiro arranque: o primeiro administrador é criado no primeiro arranque da instância. Se o campo da palavra-passe ficar vazio, a palavra-passe gerada é escrita UMA vez no log do ioBroker (abra «Logs» à esquerda e procure a linha amarela com «created with the start password») — os dois campos estão no separador «Migração e backup». A aplicação pede uma nova palavra-passe no primeiro início de sessão.</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ A conta do primeiro administrador é criada no primeiro arranque. Se o campo da palavra-passe abaixo ficar vazio, o adaptador gera uma palavra-passe aleatória e escreve-a UMA vez no log do ioBroker: abra «Logs» à esquerda no admin do ioBroker e procure a linha amarela com «created with the start password» — é essa a palavra-passe do primeiro início de sessão. A aplicação pede logo uma nova palavra-passe. Se preferir, introduza já a sua própria palavra-passe abaixo.</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = apenas este computador",
|
|
5
|
+
"Badge link secret (HMAC)": "Segredo do link do crachá (HMAC)",
|
|
6
|
+
"Bind address": "Endereço de vinculação",
|
|
7
|
+
"Calculate absences only until today": "Calcular faltas apenas até hoje",
|
|
8
|
+
"Database file (empty = adapter data directory)": "Arquivo de banco de dados (vazio = diretório de dados do adaptador)",
|
|
9
|
+
"Days users may edit on their own": "Dias em que os usuários podem editar por conta própria",
|
|
10
|
+
"Default language for new users": "Idioma padrão para novos usuários",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "vazio = uma senha aleatória é escrita uma vez no registro do adaptador; ela deve ser alterada no primeiro login",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "vazio = o adaptador gera um valor uma vez e guarda-o junto à base de dados, para que as sessões sobrevivam aos reinícios",
|
|
13
|
+
"Enable kiosk terminal": "Habilitar terminal de quiosque",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "Primeiro arranque: a palavra-passe inicial está no log do ioBroker",
|
|
15
|
+
"General": "Geral",
|
|
16
|
+
"Holiday country": "País dos feriados",
|
|
17
|
+
"Instance time zone": "Fuso horário da instância",
|
|
18
|
+
"Keep database backups for days": "Manter backups do banco de dados por dias",
|
|
19
|
+
"Login of the first administrator": "Login do primeiro administrador",
|
|
20
|
+
"Migration and backup": "Migração e backup",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "ativar apenas quando um proxy inverso está à frente do adaptador",
|
|
22
|
+
"Port": "Porta",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "Arredondar marcações rápidas para minutos (0 = desativado)",
|
|
24
|
+
"Security": "Segurança",
|
|
25
|
+
"Session lifetime in minutes": "Duração da sessão em minutos",
|
|
26
|
+
"Session secret": "Segredo da sessão",
|
|
27
|
+
"Start password of the first administrator": "Senha inicial do primeiro administrador",
|
|
28
|
+
"Subtract working time from absences": "Subtrair o tempo de trabalho das ausências",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "a porta da aplicação web, da API e do terminal; 8082 fica livre para vis e web",
|
|
30
|
+
"Time rules": "Regras de horário",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "Confiar no proxy inverso (X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "usado uma única vez: a conta é criada quando a instância ainda não tem administrador",
|
|
33
|
+
"time-tracker adapter settings": "Configurações do adaptador para time-tracker"
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Первый запуск: первый администратор создаётся при первом запуске экземпляра. Если поле пароля оставить пустым, сгенерированный пароль записывается ОДИН раз в лог ioBroker (слева откройте «Logs» и найдите жёлтую строку с «created with the start password») — оба поля находятся на вкладке «Миграция и резервное копирование». При первом входе приложение требует новый пароль.</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Учётная запись первого администратора создаётся при самом первом запуске. Если поле пароля ниже остаётся пустым, адаптер создаёт случайный пароль и записывает его ОДИН раз в лог ioBroker: откройте «Logs» слева в админке ioBroker и найдите жёлтую строку с «created with the start password» — это и есть пароль для первого входа. После этого приложение сразу требует новый пароль. Если это не нужно, введите свой пароль ниже.</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = только этот компьютер",
|
|
5
|
+
"Badge link secret (HMAC)": "Секретная ссылка на значок (HMAC)",
|
|
6
|
+
"Bind address": "Адрес привязки",
|
|
7
|
+
"Calculate absences only until today": "Рассчитывать отсутствия только до сегодняшнего дня",
|
|
8
|
+
"Database file (empty = adapter data directory)": "Файл базы данных (пустой = каталог данных адаптера)",
|
|
9
|
+
"Days users may edit on their own": "Дни, когда пользователи могут редактировать самостоятельно",
|
|
10
|
+
"Default language for new users": "Язык по умолчанию для новых пользователей",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "пусто = случайный пароль один раз записывается в журнал адаптера; его нужно сменить при первом входе",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "пусто = адаптер один раз создаёт значение и сохраняет его рядом с базой данных, чтобы сессии переживали перезапуск",
|
|
13
|
+
"Enable kiosk terminal": "Включить киоск-терминал",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "Первый запуск: стартовый пароль находится в логе ioBroker",
|
|
15
|
+
"General": "Общий",
|
|
16
|
+
"Holiday country": "Страна праздников",
|
|
17
|
+
"Instance time zone": "Часовой пояс экземпляра",
|
|
18
|
+
"Keep database backups for days": "Срок хранения резервных копий базы данных, дней",
|
|
19
|
+
"Login of the first administrator": "Логин первого администратора",
|
|
20
|
+
"Migration and backup": "Миграция и резервное копирование",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "включать только если перед адаптером стоит обратный прокси",
|
|
22
|
+
"Port": "Порт",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "Округлить быстрые отметки до минут (0 = выкл.)",
|
|
24
|
+
"Security": "Безопасность",
|
|
25
|
+
"Session lifetime in minutes": "Время жизни сессии в минутах",
|
|
26
|
+
"Session secret": "Секрет сеанса",
|
|
27
|
+
"Start password of the first administrator": "Начальный пароль первого администратора",
|
|
28
|
+
"Subtract working time from absences": "Вычитать рабочее время из отсутствий",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "порт веб-приложения, API и терминала; 8082 остаётся свободным для vis и web",
|
|
30
|
+
"Time rules": "Правила рабочего времени",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "Доверять обратному прокси (X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "используется однократно: учётная запись создаётся, когда у экземпляра ещё нет администратора",
|
|
33
|
+
"time-tracker adapter settings": "Настройки адаптера для time-tracker"
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Перший запуск: перший адміністратор створюється під час першого запуску екземпляра. Якщо поле пароля залишити порожнім, згенерований пароль записується ОДИН раз у лог ioBroker (ліворуч відкрийте «Logs» і знайдіть жовтий рядок із «created with the start password») — обидва поля на вкладці «Міграція та резервне копіювання». Під час першого входу застосунок вимагає новий пароль.</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ Обліковий запис першого адміністратора створюється під час найпершого запуску. Якщо поле пароля нижче залишити порожнім, адаптер створить випадковий пароль і запише його ОДИН раз у лог ioBroker: відкрийте «Logs» ліворуч в адмінці ioBroker і знайдіть жовтий рядок із «created with the start password» — це і є пароль для першого входу. Після цього застосунок одразу вимагає новий пароль. Якщо це не потрібно, введіть свій пароль нижче.</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = лише цей комп'ютер",
|
|
5
|
+
"Badge link secret (HMAC)": "Секрет посилання на значок (HMAC)",
|
|
6
|
+
"Bind address": "Адреса прив'язки",
|
|
7
|
+
"Calculate absences only until today": "Розраховувати відсутності лише до сьогодні",
|
|
8
|
+
"Database file (empty = adapter data directory)": "Файл бази даних (порожній = каталог даних адаптера)",
|
|
9
|
+
"Days users may edit on their own": "Дні, які користувачі можуть редагувати самостійно",
|
|
10
|
+
"Default language for new users": "Мова за умовчанням для нових користувачів",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "порожньо = випадковий пароль один раз записується в журнал адаптера; його потрібно змінити під час першого входу",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "порожньо = адаптер один раз створює значення і зберігає його поруч із базою даних, щоб сесії переживали перезапуск",
|
|
13
|
+
"Enable kiosk terminal": "Увімкнути термінал кіоску",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "Перший запуск: стартовий пароль є в лозі ioBroker",
|
|
15
|
+
"General": "Загальний",
|
|
16
|
+
"Holiday country": "Країна свят",
|
|
17
|
+
"Instance time zone": "Часовий пояс екземпляра",
|
|
18
|
+
"Keep database backups for days": "Термін зберігання резервних копій бази даних, днів",
|
|
19
|
+
"Login of the first administrator": "Логін першого адміністратора",
|
|
20
|
+
"Migration and backup": "Міграція та резервне копіювання",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "вмикати лише якщо перед адаптером стоїть зворотний проксі",
|
|
22
|
+
"Port": "Порт",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "Округліть швидкі відмітки до хвилин (0 = вимкнено)",
|
|
24
|
+
"Security": "Безпека",
|
|
25
|
+
"Session lifetime in minutes": "Тривалість сеансу в хвилинах",
|
|
26
|
+
"Session secret": "Секрет сеансу",
|
|
27
|
+
"Start password of the first administrator": "Початковий пароль першого адміністратора",
|
|
28
|
+
"Subtract working time from absences": "Віднімати робочий час від відсутностей",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "порт вебзастосунку, API та термінала; 8082 залишається вільним для vis і web",
|
|
30
|
+
"Time rules": "Правила робочого часу",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "Довіряти зворотному проксі (X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "використовується одноразово: обліковий запис створюється, коли в екземпляра ще немає адміністратора",
|
|
33
|
+
"time-tracker adapter settings": "Налаштування адаптера для time-tracker"
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ 首次启动:首个管理员在实例首次启动时创建。如果密码框留空,生成的密码会写入 ioBroker 日志一次(在左侧打开“Logs”,找到带有 “created with the start password” 的黄色行)——两个字段位于“迁移与备份”选项卡。应用在首次登录时会要求设置新密码。</div>",
|
|
3
|
+
"⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.": "<div style=\"font-size: 1.15rem; line-height: 1.6\">⚠️ 首个管理员账号在首次启动时创建。如果下面的密码框留空,适配器会生成一个随机密码,并把它写入 ioBroker 日志一次:在 ioBroker 管理界面左侧打开“Logs”,找到带有 “created with the start password” 的黄色行——那就是首次登录的密码。应用随后会立即要求设置新密码。若想跳过,请在下面直接输入自己的密码。</div>",
|
|
4
|
+
"127.0.0.1 = only this machine": "127.0.0.1 = 仅本机",
|
|
5
|
+
"Badge link secret (HMAC)": "徽章链接秘密 (HMAC)",
|
|
6
|
+
"Bind address": "绑定地址",
|
|
7
|
+
"Calculate absences only until today": "仅计算今天之前的缺勤情况",
|
|
8
|
+
"Database file (empty = adapter data directory)": "数据库文件(空=适配器数据目录)",
|
|
9
|
+
"Days users may edit on their own": "用户可以自行编辑的天数",
|
|
10
|
+
"Default language for new users": "新用户的默认语言",
|
|
11
|
+
"empty = a random password is written to the adapter log once; it has to be changed at the first login": "留空 = 随机密码会写入一次适配器日志;首次登录时必须修改",
|
|
12
|
+
"empty = the adapter generates one once and stores it next to the database, so sessions survive restarts": "留空 = 适配器会生成一次并保存在数据库旁边,这样会话在重启后仍然有效",
|
|
13
|
+
"Enable kiosk terminal": "启用自助服务终端",
|
|
14
|
+
"First start: the start password is in the ioBroker log": "首次启动:初始密码在 ioBroker 日志中",
|
|
15
|
+
"General": "常规",
|
|
16
|
+
"Holiday country": "节假日国家",
|
|
17
|
+
"Instance time zone": "实例时区",
|
|
18
|
+
"Keep database backups for days": "保留数据库备份数天",
|
|
19
|
+
"Login of the first administrator": "第一个管理员的登录名",
|
|
20
|
+
"Migration and backup": "迁移与备份",
|
|
21
|
+
"only switch this on when a reverse proxy is in front of the adapter": "仅当适配器前面有反向代理时才启用",
|
|
22
|
+
"Port": "端口",
|
|
23
|
+
"Round quick punches to minutes (0 = off)": "将快速打卡取整为分钟(0 = 关闭)",
|
|
24
|
+
"Security": "安全",
|
|
25
|
+
"Session lifetime in minutes": "会话生命周期(分钟)",
|
|
26
|
+
"Session secret": "会话密钥",
|
|
27
|
+
"Start password of the first administrator": "第一个管理员的初始密码",
|
|
28
|
+
"Subtract working time from absences": "从缺勤中减去工作时间",
|
|
29
|
+
"the port of the web app, the API and the terminal; 8082 stays free for vis and web": "网页应用、API 和终端的端口;8082 留给 vis 和 web",
|
|
30
|
+
"Time rules": "时间规则",
|
|
31
|
+
"Trust the reverse proxy (X-Forwarded-*)": "信任反向代理(X-Forwarded-*)",
|
|
32
|
+
"used once: the account is created when the instance has no administrator yet": "仅使用一次:当实例还没有管理员时会创建该账户",
|
|
33
|
+
"time-tracker adapter settings": "time-tracker 的适配器设置"
|
|
34
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
{
|
|
2
|
+
"i18n": true,
|
|
3
|
+
"type": "tabs",
|
|
4
|
+
"items": {
|
|
5
|
+
"general": {
|
|
6
|
+
"type": "panel",
|
|
7
|
+
"label": "General",
|
|
8
|
+
"items": {
|
|
9
|
+
"_firstStartHint": {
|
|
10
|
+
"type": "staticText",
|
|
11
|
+
"format": "html",
|
|
12
|
+
"text": "⚠️ First start: the first administrator is created when the instance starts for the first time. If the password field stays empty, the generated password is written ONCE into the ioBroker log (open “Logs” on the left, look for the yellow line with “created with the start password”) — both fields are in the tab “Migration and backup”. The app asks for a new password at the first login.",
|
|
13
|
+
"newLine": true,
|
|
14
|
+
"xs": 12,
|
|
15
|
+
"sm": 12,
|
|
16
|
+
"md": 12,
|
|
17
|
+
"lg": 12,
|
|
18
|
+
"xl": 12
|
|
19
|
+
},
|
|
20
|
+
"port": {
|
|
21
|
+
"type": "number",
|
|
22
|
+
"label": "Port",
|
|
23
|
+
"help": "the port of the web app, the API and the terminal; 8082 stays free for vis and web",
|
|
24
|
+
"min": 1,
|
|
25
|
+
"max": 65535,
|
|
26
|
+
"newLine": true,
|
|
27
|
+
"xs": 12,
|
|
28
|
+
"sm": 12,
|
|
29
|
+
"md": 4,
|
|
30
|
+
"lg": 3,
|
|
31
|
+
"xl": 3
|
|
32
|
+
},
|
|
33
|
+
"bind": {
|
|
34
|
+
"type": "ip",
|
|
35
|
+
"listenOnAllPorts": true,
|
|
36
|
+
"label": "Bind address",
|
|
37
|
+
"help": "127.0.0.1 = only this machine",
|
|
38
|
+
"xs": 12,
|
|
39
|
+
"sm": 12,
|
|
40
|
+
"md": 4,
|
|
41
|
+
"lg": 3,
|
|
42
|
+
"xl": 3
|
|
43
|
+
},
|
|
44
|
+
"timezone": {
|
|
45
|
+
"type": "text",
|
|
46
|
+
"label": "Instance time zone",
|
|
47
|
+
"xs": 12,
|
|
48
|
+
"sm": 12,
|
|
49
|
+
"md": 4,
|
|
50
|
+
"lg": 3,
|
|
51
|
+
"xl": 3
|
|
52
|
+
},
|
|
53
|
+
"defaultLanguage": {
|
|
54
|
+
"type": "select",
|
|
55
|
+
"label": "Default language for new users",
|
|
56
|
+
"options": [
|
|
57
|
+
{ "label": "English", "value": "en" },
|
|
58
|
+
{ "label": "Deutsch", "value": "de" },
|
|
59
|
+
{ "label": "Русский", "value": "ru" },
|
|
60
|
+
{ "label": "Português", "value": "pt" },
|
|
61
|
+
{ "label": "Nederlands", "value": "nl" },
|
|
62
|
+
{ "label": "Français", "value": "fr" },
|
|
63
|
+
{ "label": "Italiano", "value": "it" },
|
|
64
|
+
{ "label": "Español", "value": "es" },
|
|
65
|
+
{ "label": "Polski", "value": "pl" },
|
|
66
|
+
{ "label": "Українська", "value": "uk" },
|
|
67
|
+
{ "label": "中文", "value": "zh-cn" }
|
|
68
|
+
],
|
|
69
|
+
"xs": 12,
|
|
70
|
+
"sm": 12,
|
|
71
|
+
"md": 4,
|
|
72
|
+
"lg": 3,
|
|
73
|
+
"xl": 3
|
|
74
|
+
},
|
|
75
|
+
"holidayCountry": {
|
|
76
|
+
"type": "select",
|
|
77
|
+
"label": "Holiday country",
|
|
78
|
+
"options": [
|
|
79
|
+
{ "label": "Switzerland", "value": "CH" },
|
|
80
|
+
{ "label": "Germany", "value": "DE" },
|
|
81
|
+
{ "label": "Austria", "value": "AT" }
|
|
82
|
+
],
|
|
83
|
+
"newLine": true,
|
|
84
|
+
"xs": 12,
|
|
85
|
+
"sm": 12,
|
|
86
|
+
"md": 4,
|
|
87
|
+
"lg": 3,
|
|
88
|
+
"xl": 3
|
|
89
|
+
},
|
|
90
|
+
"dbPath": {
|
|
91
|
+
"type": "text",
|
|
92
|
+
"label": "Database file (empty = adapter data directory)",
|
|
93
|
+
"xs": 12,
|
|
94
|
+
"sm": 12,
|
|
95
|
+
"md": 8,
|
|
96
|
+
"lg": 6,
|
|
97
|
+
"xl": 6
|
|
98
|
+
},
|
|
99
|
+
"kioskEnabled": {
|
|
100
|
+
"type": "checkbox",
|
|
101
|
+
"label": "Enable kiosk terminal",
|
|
102
|
+
"newLine": true,
|
|
103
|
+
"xs": 12,
|
|
104
|
+
"sm": 12,
|
|
105
|
+
"md": 4,
|
|
106
|
+
"lg": 3,
|
|
107
|
+
"xl": 3
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"security": {
|
|
112
|
+
"type": "panel",
|
|
113
|
+
"label": "Security",
|
|
114
|
+
"items": {
|
|
115
|
+
"sessionSecret": {
|
|
116
|
+
"type": "password",
|
|
117
|
+
"label": "Session secret",
|
|
118
|
+
"help": "empty = the adapter generates one once and stores it next to the database, so sessions survive restarts",
|
|
119
|
+
"newLine": true,
|
|
120
|
+
"xs": 12,
|
|
121
|
+
"sm": 12,
|
|
122
|
+
"md": 6,
|
|
123
|
+
"lg": 4,
|
|
124
|
+
"xl": 4
|
|
125
|
+
},
|
|
126
|
+
"hmacSecret": {
|
|
127
|
+
"type": "password",
|
|
128
|
+
"label": "Badge link secret (HMAC)",
|
|
129
|
+
"xs": 12,
|
|
130
|
+
"sm": 12,
|
|
131
|
+
"md": 6,
|
|
132
|
+
"lg": 4,
|
|
133
|
+
"xl": 4
|
|
134
|
+
},
|
|
135
|
+
"sessionTtlMinutes": {
|
|
136
|
+
"type": "number",
|
|
137
|
+
"label": "Session lifetime in minutes",
|
|
138
|
+
"min": 5,
|
|
139
|
+
"max": 43200,
|
|
140
|
+
"xs": 12,
|
|
141
|
+
"sm": 12,
|
|
142
|
+
"md": 6,
|
|
143
|
+
"lg": 2,
|
|
144
|
+
"xl": 2
|
|
145
|
+
},
|
|
146
|
+
"editWindowDays": {
|
|
147
|
+
"type": "number",
|
|
148
|
+
"label": "Days users may edit on their own",
|
|
149
|
+
"min": 0,
|
|
150
|
+
"max": 365,
|
|
151
|
+
"xs": 12,
|
|
152
|
+
"sm": 12,
|
|
153
|
+
"md": 6,
|
|
154
|
+
"lg": 2,
|
|
155
|
+
"xl": 2
|
|
156
|
+
},
|
|
157
|
+
"trustProxy": {
|
|
158
|
+
"type": "checkbox",
|
|
159
|
+
"label": "Trust the reverse proxy (X-Forwarded-*)",
|
|
160
|
+
"help": "only switch this on when a reverse proxy is in front of the adapter",
|
|
161
|
+
"newLine": true,
|
|
162
|
+
"xs": 12,
|
|
163
|
+
"sm": 12,
|
|
164
|
+
"md": 6,
|
|
165
|
+
"lg": 4,
|
|
166
|
+
"xl": 4
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"rules": {
|
|
171
|
+
"type": "panel",
|
|
172
|
+
"label": "Time rules",
|
|
173
|
+
"items": {
|
|
174
|
+
"quickRoundMinutes": {
|
|
175
|
+
"type": "number",
|
|
176
|
+
"label": "Round quick punches to minutes (0 = off)",
|
|
177
|
+
"min": 0,
|
|
178
|
+
"max": 60,
|
|
179
|
+
"newLine": true,
|
|
180
|
+
"xs": 12,
|
|
181
|
+
"sm": 12,
|
|
182
|
+
"md": 4,
|
|
183
|
+
"lg": 3,
|
|
184
|
+
"xl": 3
|
|
185
|
+
},
|
|
186
|
+
"absenceCalcUntilToday": {
|
|
187
|
+
"type": "checkbox",
|
|
188
|
+
"label": "Calculate absences only until today",
|
|
189
|
+
"xs": 12,
|
|
190
|
+
"sm": 12,
|
|
191
|
+
"md": 4,
|
|
192
|
+
"lg": 3,
|
|
193
|
+
"xl": 3
|
|
194
|
+
},
|
|
195
|
+
"absenceDeductWorktime": {
|
|
196
|
+
"type": "checkbox",
|
|
197
|
+
"label": "Subtract working time from absences",
|
|
198
|
+
"xs": 12,
|
|
199
|
+
"sm": 12,
|
|
200
|
+
"md": 4,
|
|
201
|
+
"lg": 3,
|
|
202
|
+
"xl": 3
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"backup": {
|
|
207
|
+
"type": "panel",
|
|
208
|
+
"label": "Migration and backup",
|
|
209
|
+
"items": {
|
|
210
|
+
"_adminHintHeader": {
|
|
211
|
+
"type": "header",
|
|
212
|
+
"text": "First start: the start password is in the ioBroker log",
|
|
213
|
+
"size": 4,
|
|
214
|
+
"newLine": true,
|
|
215
|
+
"xs": 12,
|
|
216
|
+
"sm": 12,
|
|
217
|
+
"md": 12,
|
|
218
|
+
"lg": 12,
|
|
219
|
+
"xl": 12
|
|
220
|
+
},
|
|
221
|
+
"_adminHint": {
|
|
222
|
+
"type": "staticText",
|
|
223
|
+
"format": "html",
|
|
224
|
+
"text": "⚠️ The account of the first administrator is created at the very first start. If the password field below stays empty, the adapter generates a random password and writes it ONCE into the ioBroker log: open “Logs” in the ioBroker admin on the left and look for the yellow line with “created with the start password” — that is the password for the first login. The app then asks for a new password right away. Enter your own password below instead if you want to skip that.",
|
|
225
|
+
"xs": 12,
|
|
226
|
+
"sm": 12,
|
|
227
|
+
"md": 12,
|
|
228
|
+
"lg": 12,
|
|
229
|
+
"xl": 12
|
|
230
|
+
},
|
|
231
|
+
"adminLogin": {
|
|
232
|
+
"type": "text",
|
|
233
|
+
"label": "Login of the first administrator",
|
|
234
|
+
"help": "used once: the account is created when the instance has no administrator yet",
|
|
235
|
+
"newLine": true,
|
|
236
|
+
"xs": 12,
|
|
237
|
+
"sm": 12,
|
|
238
|
+
"md": 4,
|
|
239
|
+
"lg": 3,
|
|
240
|
+
"xl": 3
|
|
241
|
+
},
|
|
242
|
+
"adminPassword": {
|
|
243
|
+
"type": "password",
|
|
244
|
+
"label": "Start password of the first administrator",
|
|
245
|
+
"help": "empty = a random password is written to the adapter log once; it has to be changed at the first login",
|
|
246
|
+
"xs": 12,
|
|
247
|
+
"sm": 12,
|
|
248
|
+
"md": 4,
|
|
249
|
+
"lg": 3,
|
|
250
|
+
"xl": 3
|
|
251
|
+
},
|
|
252
|
+
"backupRetentionDays": {
|
|
253
|
+
"type": "number",
|
|
254
|
+
"label": "Keep database backups for days",
|
|
255
|
+
"min": 0,
|
|
256
|
+
"max": 3650,
|
|
257
|
+
"xs": 12,
|
|
258
|
+
"sm": 12,
|
|
259
|
+
"md": 4,
|
|
260
|
+
"lg": 2,
|
|
261
|
+
"xl": 2
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var automation_exports = {};
|
|
20
|
+
__export(automation_exports, {
|
|
21
|
+
evaluateAutomation: () => evaluateAutomation,
|
|
22
|
+
isoWeek: () => isoWeek,
|
|
23
|
+
isoWeekday: () => isoWeekday,
|
|
24
|
+
runPeriod: () => runPeriod,
|
|
25
|
+
workBlock: () => workBlock
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(automation_exports);
|
|
28
|
+
function evaluateAutomation(rule, context) {
|
|
29
|
+
var _a, _b, _c;
|
|
30
|
+
if (!rule.isActive) {
|
|
31
|
+
return { fire: false, reason: "the rule is disabled" };
|
|
32
|
+
}
|
|
33
|
+
if (context.alreadyRan) {
|
|
34
|
+
return { fire: false, reason: "it already ran for this employee today" };
|
|
35
|
+
}
|
|
36
|
+
if (!rule.weekdays.includes(context.weekday)) {
|
|
37
|
+
return { fire: false, reason: `the rule does not run on weekday ${context.weekday}` };
|
|
38
|
+
}
|
|
39
|
+
if (rule.kind === "breakReminder") {
|
|
40
|
+
if (!context.hasOpenEntry) {
|
|
41
|
+
return { fire: false, reason: "the employee is not clocked in" };
|
|
42
|
+
}
|
|
43
|
+
const length = (_a = context.blockMinutes) != null ? _a : 0;
|
|
44
|
+
const wanted2 = (_b = rule.afterMinutes) != null ? _b : 0;
|
|
45
|
+
return length >= wanted2 ? { fire: true, reason: `working for ${length} minutes without a break` } : { fire: false, reason: `working for ${length} of ${wanted2} minutes` };
|
|
46
|
+
}
|
|
47
|
+
const wanted = (_c = rule.atMinute) != null ? _c : 0;
|
|
48
|
+
if (context.minuteOfDay < wanted) {
|
|
49
|
+
return { fire: false, reason: `waiting for minute ${wanted} of the day` };
|
|
50
|
+
}
|
|
51
|
+
if (rule.kind === "clockIn") {
|
|
52
|
+
return context.hasOpenEntry ? { fire: false, reason: "the employee is already clocked in" } : { fire: true, reason: "not clocked in yet, punching in" };
|
|
53
|
+
}
|
|
54
|
+
if (!context.hasOpenEntry) {
|
|
55
|
+
return { fire: false, reason: "the employee is not clocked in" };
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
fire: true,
|
|
59
|
+
reason: rule.kind === "clockOut" ? "still clocked in, punching out" : "still clocked in"
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function isoWeekday(localDate) {
|
|
63
|
+
const [year, month, day] = localDate.split("-").map(Number);
|
|
64
|
+
const weekday = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
|
|
65
|
+
return weekday === 0 ? 7 : weekday;
|
|
66
|
+
}
|
|
67
|
+
function isoWeek(localDate) {
|
|
68
|
+
const [year, month, day] = localDate.split("-").map(Number);
|
|
69
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
70
|
+
const thursday = new Date(date);
|
|
71
|
+
thursday.setUTCDate(date.getUTCDate() + (4 - isoWeekday(localDate)));
|
|
72
|
+
const januaryFourth = new Date(Date.UTC(thursday.getUTCFullYear(), 0, 4));
|
|
73
|
+
const firstThursday = new Date(januaryFourth);
|
|
74
|
+
firstThursday.setUTCDate(januaryFourth.getUTCDate() + (4 - isoWeekday(januaryFourth.toISOString().slice(0, 10))));
|
|
75
|
+
const week = 1 + Math.round((thursday.getTime() - firstThursday.getTime()) / (7 * 864e5));
|
|
76
|
+
return `${thursday.getUTCFullYear()}-W${String(week).padStart(2, "0")}`;
|
|
77
|
+
}
|
|
78
|
+
function runPeriod(repeat, localDate) {
|
|
79
|
+
return repeat === "week" ? isoWeek(localDate) : localDate;
|
|
80
|
+
}
|
|
81
|
+
function workBlock(punches, nowUtc) {
|
|
82
|
+
const sorted = [...punches].sort((left, right) => left.tsUtc - right.tsUtc);
|
|
83
|
+
let start = null;
|
|
84
|
+
for (const punch of sorted) {
|
|
85
|
+
start = punch.direction === "in" ? punch.tsUtc : null;
|
|
86
|
+
}
|
|
87
|
+
if (start === null) {
|
|
88
|
+
return { hasOpenEntry: false, blockMinutes: null };
|
|
89
|
+
}
|
|
90
|
+
return { hasOpenEntry: true, blockMinutes: Math.max(0, Math.floor((nowUtc - start) / 60)) };
|
|
91
|
+
}
|
|
92
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
93
|
+
0 && (module.exports = {
|
|
94
|
+
evaluateAutomation,
|
|
95
|
+
isoWeek,
|
|
96
|
+
isoWeekday,
|
|
97
|
+
runPeriod,
|
|
98
|
+
workBlock
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=automation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/adapter/automation.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Automation rules of the adapter.\n *\n * The adapter checks every minute whether one of the configured rules is due. This module only *decides* \u2014 the\n * adapter loads the punches and runs the decision \u2014 so the rules stay testable without ioBroker and without a\n * clock, exactly like the trigger rules.\n *\n * The three kinds:\n * - `clockOut`: at the configured local time an employee who is still clocked in is punched out.\n * - `missingPunch`: the same moment, but only reported \u2014 nothing is written.\n * - `breakReminder`: an employee whose running work block reached the configured length is reminded.\n *\n * Every rule runs at most once per employee and period \u2014 a local date, or an ISO week for a weekly rule; the adapter\n * asks `automation_runs` before it acts. A rule can also be limited to certain weekdays.\n */\n\nimport type { AutomationRepeat, AutomationRuleRecord } from \"../db/repositories/automations\";\n\n/** What the adapter knows about one employee at the moment of a check. */\nexport interface AutomationContext {\n\t/** Local date of the employee, e.g. `2026-09-18` */\n\tlocalDate: string;\n\t/** Weekday of that date, ISO counting (1 = Monday \u2026 7 = Sunday) */\n\tweekday: number;\n\t/** Minutes since local midnight */\n\tminuteOfDay: number;\n\t/** True when the employee is clocked in */\n\thasOpenEntry: boolean;\n\t/** Minutes of the running work block, `null` when the employee is not clocked in */\n\tblockMinutes: number | null;\n\t/** True when the rule already ran for this employee today */\n\talreadyRan: boolean;\n}\n\n/** Outcome of a check. */\nexport interface AutomationDecision {\n\t/** True when the rule is due */\n\tfire: boolean;\n\t/** Why it fires or not \u2014 goes to the log and to the tests */\n\treason: string;\n}\n\n/**\n * Decides whether a rule is due for one employee.\n *\n * @param rule - rule to check\n * @param context - what the adapter knows about the employee\n * @returns the decision, including the reason for the log\n */\nexport function evaluateAutomation(rule: AutomationRuleRecord, context: AutomationContext): AutomationDecision {\n\tif (!rule.isActive) {\n\t\treturn { fire: false, reason: \"the rule is disabled\" };\n\t}\n\tif (context.alreadyRan) {\n\t\treturn { fire: false, reason: \"it already ran for this employee today\" };\n\t}\n\t// the weekday is checked before the kind: a rule for Monday to Friday stays quiet at the weekend\n\tif (!rule.weekdays.includes(context.weekday)) {\n\t\treturn { fire: false, reason: `the rule does not run on weekday ${context.weekday}` };\n\t}\n\n\tif (rule.kind === \"breakReminder\") {\n\t\tif (!context.hasOpenEntry) {\n\t\t\treturn { fire: false, reason: \"the employee is not clocked in\" };\n\t\t}\n\t\tconst length = context.blockMinutes ?? 0;\n\t\tconst wanted = rule.afterMinutes ?? 0;\n\t\treturn length >= wanted\n\t\t\t? { fire: true, reason: `working for ${length} minutes without a break` }\n\t\t\t: { fire: false, reason: `working for ${length} of ${wanted} minutes` };\n\t}\n\n\tconst wanted = rule.atMinute ?? 0;\n\tif (context.minuteOfDay < wanted) {\n\t\treturn { fire: false, reason: `waiting for minute ${wanted} of the day` };\n\t}\n\t// the mirror image of the clock out: somebody who is still missing gets a punch in\n\tif (rule.kind === \"clockIn\") {\n\t\treturn context.hasOpenEntry\n\t\t\t? { fire: false, reason: \"the employee is already clocked in\" }\n\t\t\t: { fire: true, reason: \"not clocked in yet, punching in\" };\n\t}\n\tif (!context.hasOpenEntry) {\n\t\treturn { fire: false, reason: \"the employee is not clocked in\" };\n\t}\n\treturn {\n\t\tfire: true,\n\t\treason: rule.kind === \"clockOut\" ? \"still clocked in, punching out\" : \"still clocked in\",\n\t};\n}\n\n/**\n * Weekday of a local date in ISO counting.\n *\n * @param localDate - date as `YYYY-MM-DD`\n * @returns 1 for Monday \u2026 7 for Sunday\n */\nexport function isoWeekday(localDate: string): number {\n\tconst [year, month, day] = localDate.split(\"-\").map(Number);\n\tconst weekday = new Date(Date.UTC(year, month - 1, day)).getUTCDay();\n\treturn weekday === 0 ? 7 : weekday;\n}\n\n/**\n * ISO week of a local date, e.g. `2026-W38`.\n *\n * The week belongs to the year of its Thursday, which is what makes the turn of the year come out right.\n *\n * @param localDate - date as `YYYY-MM-DD`\n * @returns year and week\n */\nexport function isoWeek(localDate: string): string {\n\tconst [year, month, day] = localDate.split(\"-\").map(Number);\n\tconst date = new Date(Date.UTC(year, month - 1, day));\n\tconst thursday = new Date(date);\n\tthursday.setUTCDate(date.getUTCDate() + (4 - isoWeekday(localDate)));\n\t// the 4th of January is always in the first ISO week, so its Thursday is the reference point\n\tconst januaryFourth = new Date(Date.UTC(thursday.getUTCFullYear(), 0, 4));\n\tconst firstThursday = new Date(januaryFourth);\n\tfirstThursday.setUTCDate(januaryFourth.getUTCDate() + (4 - isoWeekday(januaryFourth.toISOString().slice(0, 10))));\n\tconst week = 1 + Math.round((thursday.getTime() - firstThursday.getTime()) / (7 * 86400000));\n\treturn `${thursday.getUTCFullYear()}-W${String(week).padStart(2, \"0\")}`;\n}\n\n/**\n * Period a rule counts in.\n *\n * @param repeat - whether the rule may act once a day or once a week\n * @param localDate - date as `YYYY-MM-DD`\n * @returns the local date, or the ISO week for a weekly rule\n */\nexport function runPeriod(repeat: AutomationRepeat, localDate: string): string {\n\treturn repeat === \"week\" ? isoWeek(localDate) : localDate;\n}\n\n/**\n * Reads the running work block of an employee from the punches of the day.\n *\n * The direction hints of the punches are used, which is what the day view shows as well; the authoritative pairing\n * of a day (and therefore the punch the adapter writes) stays with `domain/punch`. A reminder is advisory, so the\n * hint is good enough here \u2014 and an employee who is not clocked in has no block at all.\n *\n * @param punches - punches of the local day, any order\n * @param nowUtc - instant of the check, UTC epoch seconds\n * @returns true when the employee is clocked in, plus the minutes of the running block\n */\nexport function workBlock(\n\tpunches: { tsUtc: number; direction: string }[],\n\tnowUtc: number,\n): { hasOpenEntry: boolean; blockMinutes: number | null } {\n\tconst sorted = [...punches].sort((left, right) => left.tsUtc - right.tsUtc);\n\tlet start: number | null = null;\n\tfor (const punch of sorted) {\n\t\tstart = punch.direction === \"in\" ? punch.tsUtc : null;\n\t}\n\tif (start === null) {\n\t\treturn { hasOpenEntry: false, blockMinutes: null };\n\t}\n\treturn { hasOpenEntry: true, blockMinutes: Math.max(0, Math.floor((nowUtc - start) / 60)) };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiDO,SAAS,mBAAmB,MAA4B,SAAgD;AAjD/G;AAkDC,MAAI,CAAC,KAAK,UAAU;AACnB,WAAO,EAAE,MAAM,OAAO,QAAQ,uBAAuB;AAAA,EACtD;AACA,MAAI,QAAQ,YAAY;AACvB,WAAO,EAAE,MAAM,OAAO,QAAQ,yCAAyC;AAAA,EACxE;AAEA,MAAI,CAAC,KAAK,SAAS,SAAS,QAAQ,OAAO,GAAG;AAC7C,WAAO,EAAE,MAAM,OAAO,QAAQ,oCAAoC,QAAQ,OAAO,GAAG;AAAA,EACrF;AAEA,MAAI,KAAK,SAAS,iBAAiB;AAClC,QAAI,CAAC,QAAQ,cAAc;AAC1B,aAAO,EAAE,MAAM,OAAO,QAAQ,iCAAiC;AAAA,IAChE;AACA,UAAM,UAAS,aAAQ,iBAAR,YAAwB;AACvC,UAAMA,WAAS,UAAK,iBAAL,YAAqB;AACpC,WAAO,UAAUA,UACd,EAAE,MAAM,MAAM,QAAQ,eAAe,MAAM,2BAA2B,IACtE,EAAE,MAAM,OAAO,QAAQ,eAAe,MAAM,OAAOA,OAAM,WAAW;AAAA,EACxE;AAEA,QAAM,UAAS,UAAK,aAAL,YAAiB;AAChC,MAAI,QAAQ,cAAc,QAAQ;AACjC,WAAO,EAAE,MAAM,OAAO,QAAQ,sBAAsB,MAAM,cAAc;AAAA,EACzE;AAEA,MAAI,KAAK,SAAS,WAAW;AAC5B,WAAO,QAAQ,eACZ,EAAE,MAAM,OAAO,QAAQ,qCAAqC,IAC5D,EAAE,MAAM,MAAM,QAAQ,kCAAkC;AAAA,EAC5D;AACA,MAAI,CAAC,QAAQ,cAAc;AAC1B,WAAO,EAAE,MAAM,OAAO,QAAQ,iCAAiC;AAAA,EAChE;AACA,SAAO;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,KAAK,SAAS,aAAa,mCAAmC;AAAA,EACvE;AACD;AAQO,SAAS,WAAW,WAA2B;AACrD,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,UAAU,MAAM,GAAG,EAAE,IAAI,MAAM;AAC1D,QAAM,UAAU,IAAI,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC,EAAE,UAAU;AACnE,SAAO,YAAY,IAAI,IAAI;AAC5B;AAUO,SAAS,QAAQ,WAA2B;AAClD,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI,UAAU,MAAM,GAAG,EAAE,IAAI,MAAM;AAC1D,QAAM,OAAO,IAAI,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC;AACpD,QAAM,WAAW,IAAI,KAAK,IAAI;AAC9B,WAAS,WAAW,KAAK,WAAW,KAAK,IAAI,WAAW,SAAS,EAAE;AAEnE,QAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,SAAS,eAAe,GAAG,GAAG,CAAC,CAAC;AACxE,QAAM,gBAAgB,IAAI,KAAK,aAAa;AAC5C,gBAAc,WAAW,cAAc,WAAW,KAAK,IAAI,WAAW,cAAc,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE;AAChH,QAAM,OAAO,IAAI,KAAK,OAAO,SAAS,QAAQ,IAAI,cAAc,QAAQ,MAAM,IAAI,MAAS;AAC3F,SAAO,GAAG,SAAS,eAAe,CAAC,KAAK,OAAO,IAAI,EAAE,SAAS,GAAG,GAAG,CAAC;AACtE;AASO,SAAS,UAAU,QAA0B,WAA2B;AAC9E,SAAO,WAAW,SAAS,QAAQ,SAAS,IAAI;AACjD;AAaO,SAAS,UACf,SACA,QACyD;AACzD,QAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK;AAC1E,MAAI,QAAuB;AAC3B,aAAW,SAAS,QAAQ;AAC3B,YAAQ,MAAM,cAAc,OAAO,MAAM,QAAQ;AAAA,EAClD;AACA,MAAI,UAAU,MAAM;AACnB,WAAO,EAAE,cAAc,OAAO,cAAc,KAAK;AAAA,EAClD;AACA,SAAO,EAAE,cAAc,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE;AAC3F;",
|
|
6
|
+
"names": ["wanted"]
|
|
7
|
+
}
|