diff --git a/Backend/endpoints/team.go b/Backend/endpoints/team.go
index e026488..397d45a 100644
--- a/Backend/endpoints/team.go
+++ b/Backend/endpoints/team.go
@@ -79,5 +79,5 @@ func showWeeks(w http.ResponseWriter, r *http.Request) {
workWeeks = append(workWeeks, weeks...)
}
// isRunningWeek := time.Since(lastSub) < 24*5*time.Hour //the last submission is this week and cannot be send yet
- templates.TeamPage([]models.WorkWeek{userWeek, userWeek}, userWeek).Render(r.Context(), w)
+ templates.TeamPage(workWeeks, userWeek).Render(r.Context(), w)
}
diff --git a/Backend/models/absence.go b/Backend/models/absence.go
index 7d9e913..e3296a4 100644
--- a/Backend/models/absence.go
+++ b/Backend/models/absence.go
@@ -45,6 +45,10 @@ func (a *Absence) Date() time.Time {
return a.Day.Truncate(24 * time.Hour)
}
+func (a *Absence) IsMultiDay() bool {
+ return !a.DateFrom.Equal(a.DateTo)
+}
+
func (a *Absence) TimeWorkVirtual(u User) time.Duration {
return a.TimeWorkReal(u)
}
diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go
index 5a99af4..cde6dd3 100644
--- a/Backend/models/workDay.go
+++ b/Backend/models/workDay.go
@@ -3,9 +3,9 @@ package models
import (
"arbeitszeitmessung/helper"
"encoding/json"
+ "fmt"
"log"
"sort"
- "strconv"
"time"
)
@@ -87,8 +87,8 @@ func (d *WorkDay) TimeWorkVirtual(u User) time.Duration {
return d.workTime
}
-func (d *WorkDay) GetKurzArbeit() Absence {
- return d.kurzArbeitAbsence
+func (d *WorkDay) GetKurzArbeit() *Absence {
+ return &d.kurzArbeitAbsence
}
func (d *WorkDay) TimeWorkReal(u User) time.Duration {
@@ -144,7 +144,7 @@ func (d *WorkDay) TimePauseReal(u User) (work, pause time.Duration) {
}
func (d *WorkDay) ToString() string {
- return "WorkDay"
+ return fmt.Sprintf("WorkDay: %s with %d bookings and worktime: %s", d.Date().Format("2006-01-02"), len(d.Bookings), helper.FormatDuration(d.workTime))
}
func (d *WorkDay) IsWorkDay() bool {
@@ -231,7 +231,7 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
return workDays
}
defer rows.Close()
- emptyDays, _ := strconv.ParseBool(helper.GetEnv("EMPTY_DAYS", "false"))
+ // emptyDays, _ := strconv.ParseBool(helper.GetEnv("EMPTY_DAYS", "false"))
for rows.Next() {
var workDay WorkDay
var bookings []byte
@@ -251,11 +251,12 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
workDay.Bookings = []Booking{}
}
workDay.TimePauseReal(user)
- if emptyDays && !helper.IsWeekend(workDay.Date()) {
+ if len(workDay.Bookings) > 1 || !helper.IsWeekend(workDay.Date()) {
workDays = append(workDays, workDay)
}
}
if err = rows.Err(); err != nil {
+ log.Println("Error in workday rows!", err)
return workDays
}
return workDays
diff --git a/Backend/src/main.css b/Backend/src/main.css
index 9afdfb3..85052e2 100644
--- a/Backend/src/main.css
+++ b/Backend/src/main.css
@@ -110,6 +110,31 @@
color: var(--color-neutral-800);
}
+ .edit-box {
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ border-color: var(--color-neutral-500);
+ transition-property: background-color, border-color;
+ transition-timing-function: var(--default-transition-timing-function) * 2;
+ transition-duration: var(--default-transition-duration);
+ outline: none;
+
+ &:is(:where(.group):is(.edit) *) {
+ border-width: 1px;
+ }
+ }
+
+ .edit-box:hover {
+ &:is(:where(.group):is(.edit) *) {
+ background-color: var(--color-white);
+ border-color: var(--color-neutral-300);
+ }
+ }
+
+ .edit-box input:focus {
+ outline: none;
+ }
+
@media (width >=48rem) {
.grid-main {
grid-template-columns: repeat(5, 1fr);
diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css
index 1e919bf..387452a 100644
--- a/Backend/static/css/styles.css
+++ b/Backend/static/css/styles.css
@@ -21,7 +21,6 @@
--color-neutral-600: oklch(43.9% 0 0);
--color-neutral-700: oklch(37.1% 0 0);
--color-neutral-800: oklch(26.9% 0 0);
- --color-neutral-900: oklch(20.5% 0 0);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
@@ -198,14 +197,14 @@
.relative {
position: relative;
}
- .top-2 {
- top: calc(var(--spacing) * 2);
- }
.top-2\.5 {
top: calc(var(--spacing) * 2.5);
}
- .right-2 {
- right: calc(var(--spacing) * 2);
+ .top-\[0\.125rem\] {
+ top: 0.125rem;
+ }
+ .right-1 {
+ right: calc(var(--spacing) * 1);
}
.right-2\.5 {
right: calc(var(--spacing) * 2.5);
@@ -237,19 +236,6 @@
.ml-1 {
margin-left: calc(var(--spacing) * 1);
}
- .icon-\[material-symbols-light--add-circle-outline\] {
- display: inline-block;
- width: 1.25em;
- height: 1.25em;
- background-color: currentColor;
- -webkit-mask-image: var(--svg);
- mask-image: var(--svg);
- -webkit-mask-repeat: no-repeat;
- mask-repeat: no-repeat;
- -webkit-mask-size: 100% 100%;
- mask-size: 100% 100%;
- --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M11.5 16.5h1v-4h4v-1h-4v-4h-1v4h-4v1h4zm.503 4.5q-1.867 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709M12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8'/%3E%3C/svg%3E");
- }
.icon-\[material-symbols-light--check-circle-outline\] {
display: inline-block;
width: 1.25em;
@@ -367,18 +353,6 @@
width: calc(var(--spacing) * 4);
height: calc(var(--spacing) * 4);
}
- .size-5 {
- width: calc(var(--spacing) * 5);
- height: calc(var(--spacing) * 5);
- }
- .size-6 {
- width: calc(var(--spacing) * 6);
- height: calc(var(--spacing) * 6);
- }
- .size-7 {
- width: calc(var(--spacing) * 7);
- height: calc(var(--spacing) * 7);
- }
.h-2 {
height: calc(var(--spacing) * 2);
}
@@ -406,9 +380,6 @@
.w-5 {
width: calc(var(--spacing) * 5);
}
- .w-9 {
- width: calc(var(--spacing) * 9);
- }
.w-9\/10 {
width: calc(9/10 * 100%);
}
@@ -421,20 +392,14 @@
.w-full {
width: 100%;
}
- .flex-shrink {
- flex-shrink: 1;
- }
.flex-shrink-0 {
flex-shrink: 0;
}
- .shrink {
- flex-shrink: 1;
- }
.flex-grow {
flex-grow: 1;
}
- .grow {
- flex-grow: 1;
+ .grow-0 {
+ flex-grow: 0;
}
.grow-1 {
flex-grow: 1;
@@ -442,18 +407,9 @@
.basis-\[content\] {
flex-basis: content;
}
- .basis-auto {
- flex-basis: auto;
- }
- .border-collapse {
- border-collapse: collapse;
- }
.cursor-pointer {
cursor: pointer;
}
- .resize {
- resize: both;
- }
.scroll-m-2 {
scroll-margin: calc(var(--spacing) * 2);
}
@@ -551,10 +507,17 @@
.rounded-md {
border-radius: var(--radius-md);
}
+ .rounded-none {
+ border-radius: 0;
+ }
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
+ .border-0 {
+ border-style: var(--tw-border-style);
+ border-width: 0px;
+ }
.border-r-0 {
border-right-style: var(--tw-border-style);
border-right-width: 0px;
@@ -567,18 +530,19 @@
border-bottom-style: var(--tw-border-style);
border-bottom-width: 0px;
}
- .border-neutral-200 {
- border-color: var(--color-neutral-200);
+ .border-dashed {
+ --tw-border-style: dashed;
+ border-style: dashed;
}
.border-neutral-300 {
border-color: var(--color-neutral-300);
}
+ .border-neutral-500 {
+ border-color: var(--color-neutral-500);
+ }
.border-neutral-600 {
border-color: var(--color-neutral-600);
}
- .border-neutral-900 {
- border-color: var(--color-neutral-900);
- }
.bg-accent {
background-color: var(--color-accent);
}
@@ -600,9 +564,6 @@
.bg-red-600 {
background-color: var(--color-red-600);
}
- .mask-repeat {
- mask-repeat: repeat;
- }
.p-1 {
padding: calc(var(--spacing) * 1);
}
@@ -646,6 +607,9 @@
.text-accent {
color: var(--color-accent);
}
+ .text-black {
+ color: var(--color-black);
+ }
.text-neutral-300 {
color: var(--color-neutral-300);
}
@@ -670,13 +634,6 @@
.uppercase {
text-transform: uppercase;
}
- .underline {
- text-decoration-line: underline;
- }
- .outline {
- outline-style: var(--tw-outline-style);
- outline-width: 1px;
- }
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
@@ -720,6 +677,11 @@
}
}
}
+ .group-\[\.edit\]\:ml-2 {
+ &:is(:where(.group):is(.edit) *) {
+ margin-left: calc(var(--spacing) * 2);
+ }
+ }
.group-\[\.edit\]\:block {
&:is(:where(.group):is(.edit) *) {
display: block;
@@ -745,13 +707,6 @@
color: var(--color-neutral-400);
}
}
- .hover\:border-neutral-300 {
- &:hover {
- @media (hover: hover) {
- border-color: var(--color-neutral-300);
- }
- }
- }
.hover\:border-neutral-500 {
&:hover {
@media (hover: hover) {
@@ -773,13 +728,6 @@
}
}
}
- .hover\:bg-red-500 {
- &:hover {
- @media (hover: hover) {
- background-color: var(--color-red-500);
- }
- }
- }
.hover\:bg-red-700 {
&:hover {
@media (hover: hover) {
@@ -787,13 +735,6 @@
}
}
}
- .hover\:text-accent {
- &:hover {
- @media (hover: hover) {
- color: var(--color-accent);
- }
- }
- }
.hover\:text-white {
&:hover {
@media (hover: hover) {
@@ -801,11 +742,6 @@
}
}
}
- .focus\:border-neutral-400 {
- &:focus {
- border-color: var(--color-neutral-400);
- }
- }
.focus\:bg-neutral-700 {
&:focus {
background-color: var(--color-neutral-700);
@@ -1028,6 +964,27 @@
background-color: var(--color-neutral-100);
color: var(--color-neutral-800);
}
+ .edit-box {
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ border-color: var(--color-neutral-500);
+ transition-property: background-color, border-color;
+ transition-timing-function: var(--default-transition-timing-function) * 2;
+ transition-duration: var(--default-transition-duration);
+ outline: none;
+ &:is(:where(.group):is(.edit) *) {
+ border-width: 1px;
+ }
+ }
+ .edit-box:hover {
+ &:is(:where(.group):is(.edit) *) {
+ background-color: var(--color-white);
+ border-color: var(--color-neutral-300);
+ }
+ }
+ .edit-box input:focus {
+ outline: none;
+ }
@media (width >=48rem) {
.grid-main {
grid-template-columns: repeat(5, 1fr);
@@ -1060,11 +1017,6 @@
syntax: "*";
inherits: false;
}
-@property --tw-outline-style {
- syntax: "*";
- inherits: false;
- initial-value: solid;
-}
@property --tw-blur {
syntax: "*";
inherits: false;
@@ -1129,7 +1081,6 @@
--tw-border-style: solid;
--tw-divide-y-reverse: 0;
--tw-font-weight: initial;
- --tw-outline-style: solid;
--tw-blur: initial;
--tw-brightness: initial;
--tw-contrast: initial;
diff --git a/Backend/static/script.js b/Backend/static/script.js
index e5f27bd..04bae89 100644
--- a/Backend/static/script.js
+++ b/Backend/static/script.js
@@ -12,21 +12,22 @@ function editDay(element, event, formId) {
}
}
+function syncFields(from, to, fieldsToSync) {
+ fieldsToSync.forEach((name) => {
+ const src = from.querySelector(`[name=${name}]`);
+ const target = to.querySelector(`[name=${name}]`);
+ if (!src || !target) return;
+ target.value = src.value;
+ });
+}
+
function editAbsence(element, event, absenceId) {
+ event.preventDefault();
var form = document.getElementById("absence_form");
- console.log(absenceId);
if (absenceId != 0) {
- const fieldsToSync = ["date_from", "date_to", "aw_type", "aw_id"];
-
var dataForm = document.getElementById(absenceId);
-
- fieldsToSync.forEach((name) => {
- const src = dataForm.querySelector(`[name=${name}]`);
- const target = form.querySelector(`[name=${name}]`);
- if (!src || !target) return;
- target.value = src.value;
- });
+ syncFields(dataForm, form, ["date_from", "date_to", "aw_type", "aw_id"]);
} else {
var dataForm = element.closest(".grid-sub").querySelector(".all-booking-component > form");
form.querySelector("[name=date_from]").value = dataForm.id.replace("time-", "");
diff --git a/Backend/templates/timeComponents.templ b/Backend/templates/timeComponents.templ
index f50e3a3..413c16b 100644
--- a/Backend/templates/timeComponents.templ
+++ b/Backend/templates/timeComponents.templ
@@ -124,31 +124,56 @@ templ timeGaugeComponent(progress int8, today bool) {
}
templ newAbsenceComponent() {
-
-
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -503,7 +467,7 @@ func defaultDayComponent(day models.IWorkDay) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -527,64 +491,64 @@ func absentInput(a models.Absence) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var22 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var22 == nil {
- templ_7745c5c3_Var22 = templ.NopComponent
+ templ_7745c5c3_Var20 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var20 == nil {
+ templ_7745c5c3_Var20 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/DB/initdb/01_schema.sql b/DB/initdb/01_schema.sql
index 56b52d9..e3e795f 100644
--- a/DB/initdb/01_schema.sql
+++ b/DB/initdb/01_schema.sql
@@ -40,11 +40,11 @@ CREATE TABLE "s_personal_daten" (
"geschlecht" int2,
"card_uid" varchar(255),
"hauptbeschaeftigungs_ort" int2,
- "arbeitszeit_per_tag" float4 NOT NULL,
- "arbeitszeit_per_woche" float4 NOT NULL,
+ "arbeitszeit_per_tag" float4,
+ "arbeitszeit_per_woche" float4,
"arbeitszeit_min_start" time(6),
"arbeitszeit_max_ende" time(6),
- "vorgesetzter_pers_nr" int4 NOT NULL
+ "vorgesetzter_pers_nr" int4
);
COMMENT ON COLUMN "s_personal_daten"."geschlecht" IS '1==weiblich, 2==maennlich, 3==divers';
diff --git a/Makefile b/Makefile
index 994d36c..283ab33 100644
--- a/Makefile
+++ b/Makefile
@@ -44,8 +44,8 @@ generateFrontend:
backend: generateFrontend login_registry
- docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:latest Backend --push
- docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:${GIT_COMMIT} Backend --push
+ docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:latest Backend --load #--push
+ # docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeitmessung:${GIT_COMMIT} Backend //--push
test:
$(MAKE) -C Backend test
diff --git a/migrations/20250916093608_kurzarbeit.down.sql b/migrations/20250916093608_kurzarbeit.down.sql
index 697259f..c3e5291 100644
--- a/migrations/20250916093608_kurzarbeit.down.sql
+++ b/migrations/20250916093608_kurzarbeit.down.sql
@@ -1,8 +1,6 @@
-- reverse: modify "wochen_report" table
ALTER TABLE "wochen_report" ALTER COLUMN "personal_nummer" DROP NOT NULL;
-- reverse: modify "s_personal_daten" table
-ALTER TABLE "s_personal_daten" ALTER COLUMN "arbeitszeit_per_woche" DROP NOT NULL, ALTER COLUMN "vorgesetzter_pers_nr" DROP NOT NULL, ALTER COLUMN "arbeitszeit_per_tag" DROP NOT NULL;
--- reverse: modify "s_anwesenheit_typen" table
ALTER TABLE "s_anwesenheit_typen" ALTER COLUMN "anwesenheit_name" DROP NOT NULL;
-- reverse: set comment to column: "arbeitszeit_equivalent" on table: "s_abwesenheit_typen"
COMMENT ON COLUMN "s_abwesenheit_typen"."arbeitszeit_equivalent" IS NULL;
diff --git a/migrations/20250916093608_kurzarbeit.up.sql b/migrations/20250916093608_kurzarbeit.up.sql
index b944343..beb69ae 100644
--- a/migrations/20250916093608_kurzarbeit.up.sql
+++ b/migrations/20250916093608_kurzarbeit.up.sql
@@ -8,6 +8,4 @@ COMMENT ON COLUMN "s_abwesenheit_typen"."arbeitszeit_equivalent" IS '0=keine Arb
-- modify "s_anwesenheit_typen" table
ALTER TABLE "s_anwesenheit_typen" ALTER COLUMN "anwesenheit_name" SET NOT NULL;
-- modify "s_personal_daten" table
-ALTER TABLE "s_personal_daten" ALTER COLUMN "arbeitszeit_per_tag" SET NOT NULL, ALTER COLUMN "vorgesetzter_pers_nr" SET NOT NULL, ALTER COLUMN "arbeitszeit_per_woche" SET NOT NULL;
--- modify "wochen_report" table
ALTER TABLE "wochen_report" ALTER COLUMN "personal_nummer" SET NOT NULL;