@masterteam/system-settings 0.0.9 → 0.0.11

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.
@@ -15,6 +15,7 @@ import { ToastService } from '@masterteam/components/toast';
15
15
  import * as i1$1 from 'primeng/skeleton';
16
16
  import { SkeletonModule } from 'primeng/skeleton';
17
17
  import { Card } from '@masterteam/components/card';
18
+ import { RadioCardsField } from '@masterteam/components/radio-cards-field';
18
19
  import { MultiSelectField } from '@masterteam/components/multi-select-field';
19
20
  import { SelectField } from '@masterteam/components/select-field';
20
21
  import { ModalRef } from '@masterteam/components/dialog';
@@ -25,6 +26,22 @@ import { NumberField } from '@masterteam/components/number-field';
25
26
  import { TextareaField } from '@masterteam/components/textarea-field';
26
27
  import { ToggleField } from '@masterteam/components/toggle-field';
27
28
 
29
+ /**
30
+ * "General Configuration" — product-wide application behaviour that is not tied
31
+ * to a specific feature area. Currently holds the explore landing view; more
32
+ * entries are expected to land in this card.
33
+ */
34
+ class SystemSettingsGeneralConfigSection {
35
+ generalConfigurationForm = input.required(...(ngDevMode ? [{ debugName: "generalConfigurationForm" }] : /* istanbul ignore next */ []));
36
+ exploreDefaultViewOptions = input([], ...(ngDevMode ? [{ debugName: "exploreDefaultViewOptions" }] : /* istanbul ignore next */ []));
37
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsGeneralConfigSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
38
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: SystemSettingsGeneralConfigSection, isStandalone: true, selector: "mt-system-settings-general-config-section", inputs: { generalConfigurationForm: { classPropertyName: "generalConfigurationForm", publicName: "generalConfigurationForm", isSignal: true, isRequired: true, transformFunction: null }, exploreDefaultViewOptions: { classPropertyName: "exploreDefaultViewOptions", publicName: "exploreDefaultViewOptions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"generalConfigurationForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"general-configuration-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"general-configuration-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-radio-cards-field\r\n formControlName=\"defaultExploreView\"\r\n [options]=\"exploreDefaultViewOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('explore-default-view')\"\r\n [hint]=\"t('explore-default-view-hint')\"\r\n [required]=\"true\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: RadioCardsField, selector: "mt-radio-cards-field", inputs: ["circle", "label", "hint", "readonly", "required", "color", "size", "optionLabel", "optionValue", "options"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
39
+ }
40
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsGeneralConfigSection, decorators: [{
41
+ type: Component,
42
+ args: [{ selector: 'mt-system-settings-general-config-section', imports: [ReactiveFormsModule, TranslocoDirective, Card, RadioCardsField], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"generalConfigurationForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"general-configuration-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"general-configuration-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-radio-cards-field\r\n formControlName=\"defaultExploreView\"\r\n [options]=\"exploreDefaultViewOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('explore-default-view')\"\r\n [hint]=\"t('explore-default-view-hint')\"\r\n [required]=\"true\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
43
+ }], propDecorators: { generalConfigurationForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "generalConfigurationForm", required: true }] }], exploreDefaultViewOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "exploreDefaultViewOptions", required: false }] }] } });
44
+
28
45
  class SystemSettingsGeneralSection {
29
46
  timezoneForm = input.required(...(ngDevMode ? [{ debugName: "timezoneForm" }] : /* istanbul ignore next */ []));
30
47
  currencyForm = input.required(...(ngDevMode ? [{ debugName: "currencyForm" }] : /* istanbul ignore next */ []));
@@ -189,13 +206,11 @@ class SystemSettingsTimeSheetSection {
189
206
  policyForm = input.required(...(ngDevMode ? [{ debugName: "policyForm" }] : /* istanbul ignore next */ []));
190
207
  globalWorkingHoursForm = input.required(...(ngDevMode ? [{ debugName: "globalWorkingHoursForm" }] : /* istanbul ignore next */ []));
191
208
  dayOptions = input([], ...(ngDevMode ? [{ debugName: "dayOptions" }] : /* istanbul ignore next */ []));
192
- scheduleItemTypeOptions = input([], ...(ngDevMode ? [{ debugName: "scheduleItemTypeOptions" }] : /* istanbul ignore next */ []));
193
- rateSourceOptions = input([], ...(ngDevMode ? [{ debugName: "rateSourceOptions" }] : /* istanbul ignore next */ []));
209
+ frequencyOptions = input([], ...(ngDevMode ? [{ debugName: "frequencyOptions" }] : /* istanbul ignore next */ []));
194
210
  timezoneOptions = input([], ...(ngDevMode ? [{ debugName: "timezoneOptions" }] : /* istanbul ignore next */ []));
195
- allowOvertimeControl = computed(() => this.policyForm().get('allowOvertime'), ...(ngDevMode ? [{ debugName: "allowOvertimeControl" }] : /* istanbul ignore next */ []));
196
- costEnabledControl = computed(() => this.policyForm().get('costEnabled'), ...(ngDevMode ? [{ debugName: "costEnabledControl" }] : /* istanbul ignore next */ []));
211
+ maxDailyBelowDaily = input(false, ...(ngDevMode ? [{ debugName: "maxDailyBelowDaily" }] : /* istanbul ignore next */ []));
197
212
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsTimeSheetSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
198
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: SystemSettingsTimeSheetSection, isStandalone: true, selector: "mt-system-settings-timesheet-section", inputs: { policyForm: { classPropertyName: "policyForm", publicName: "policyForm", isSignal: true, isRequired: true, transformFunction: null }, globalWorkingHoursForm: { classPropertyName: "globalWorkingHoursForm", publicName: "globalWorkingHoursForm", isSignal: true, isRequired: true, transformFunction: null }, dayOptions: { classPropertyName: "dayOptions", publicName: "dayOptions", isSignal: true, isRequired: false, transformFunction: null }, scheduleItemTypeOptions: { classPropertyName: "scheduleItemTypeOptions", publicName: "scheduleItemTypeOptions", isSignal: true, isRequired: false, transformFunction: null }, rateSourceOptions: { classPropertyName: "rateSourceOptions", publicName: "rateSourceOptions", isSignal: true, isRequired: false, transformFunction: null }, timezoneOptions: { classPropertyName: "timezoneOptions", publicName: "timezoneOptions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-2 mb-6\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"policyForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"timesheet-policy-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"timesheet-policy-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div\r\n class=\"rounded-lg border border-sky-200 bg-sky-50 px-4 py-3 text-sm text-sky-800\"\r\n >\r\n {{ t(\"timesheet-policy-workflow-note\") }}\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"weekStartDay\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('week-start-day')\"\r\n [placeholder]=\"t('week-start-day-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n formControlName=\"allowedScheduleItemTypes\"\r\n [options]=\"scheduleItemTypeOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'itemType'\"\r\n [label]=\"t('allowed-schedule-item-types')\"\r\n [placeholder]=\"t('allowed-schedule-item-types-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"regularDailyHours\"\r\n [label]=\"t('regular-daily-hours')\"\r\n [placeholder]=\"t('regular-daily-hours-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"maxDailyHours\"\r\n [label]=\"t('max-daily-hours')\"\r\n [placeholder]=\"t('max-daily-hours-placeholder')\"\r\n [min]=\"1\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"pastEntryLockDays\"\r\n [label]=\"t('past-entry-lock-days')\"\r\n [placeholder]=\"t('past-entry-lock-days-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"3650\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"rateSource\"\r\n [options]=\"rateSourceOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('rate-source')\"\r\n [placeholder]=\"t('rate-source-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n <mt-toggle-field\r\n formControlName=\"generationEnabled\"\r\n [label]=\"t('generation-enabled')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"manualGenerationEnabled\"\r\n [label]=\"t('manual-generation-enabled')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowOvertime\"\r\n [label]=\"t('allow-overtime')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"requireOvertimeReason\"\r\n [label]=\"t('require-overtime-reason')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"requireDescription\"\r\n [label]=\"t('require-description')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowFutureEntry\"\r\n [label]=\"t('allow-future-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"assignedItemsOnly\"\r\n [label]=\"t('assigned-items-only')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowZeroHourSubmit\"\r\n [label]=\"t('allow-zero-hour-submit')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"costEnabled\"\r\n [label]=\"t('cost-enabled')\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"globalWorkingHoursForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"global-working-hours-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"global-working-hours-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"timeZoneId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('global-timezone')\"\r\n [placeholder]=\"t('global-timezone-placeholder')\"\r\n [filter]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"workDayStart\"\r\n type=\"time\"\r\n [label]=\"t('work-day-start')\"\r\n [placeholder]=\"t('work-day-start-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"workDayEnd\"\r\n type=\"time\"\r\n [label]=\"t('work-day-end')\"\r\n [placeholder]=\"t('work-day-end-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"workingDays\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('working-days')\"\r\n [placeholder]=\"t('working-days-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-textarea-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"holidaysCsv\"\r\n [label]=\"t('global-holidays')\"\r\n [placeholder]=\"t('global-holidays-placeholder')\"\r\n rows=\"3\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
213
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: SystemSettingsTimeSheetSection, isStandalone: true, selector: "mt-system-settings-timesheet-section", inputs: { policyForm: { classPropertyName: "policyForm", publicName: "policyForm", isSignal: true, isRequired: true, transformFunction: null }, globalWorkingHoursForm: { classPropertyName: "globalWorkingHoursForm", publicName: "globalWorkingHoursForm", isSignal: true, isRequired: true, transformFunction: null }, dayOptions: { classPropertyName: "dayOptions", publicName: "dayOptions", isSignal: true, isRequired: false, transformFunction: null }, frequencyOptions: { classPropertyName: "frequencyOptions", publicName: "frequencyOptions", isSignal: true, isRequired: false, transformFunction: null }, timezoneOptions: { classPropertyName: "timezoneOptions", publicName: "timezoneOptions", isSignal: true, isRequired: false, transformFunction: null }, maxDailyBelowDaily: { classPropertyName: "maxDailyBelowDaily", publicName: "maxDailyBelowDaily", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-2 mb-6\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"policyForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"general-card-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"general-card-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"frequency\"\r\n [options]=\"frequencyOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('frequency')\"\r\n [placeholder]=\"t('frequency-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"maxDailyHours\"\r\n [label]=\"t('max-daily-hours')\"\r\n [placeholder]=\"t('max-daily-hours-placeholder')\"\r\n [min]=\"1\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n [hint]=\"maxDailyBelowDaily() ? t('max-daily-below-daily') : ''\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"submissionDeadlineDays\"\r\n [label]=\"t('submission-deadline-days')\"\r\n [placeholder]=\"t('submission-deadline-days-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"90\"\r\n [required]=\"true\"\r\n [hint]=\"t('submission-deadline-hint')\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n <mt-toggle-field\r\n formControlName=\"requireDescription\"\r\n [label]=\"t('require-description')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowFutureEntry\"\r\n [label]=\"t('allow-future-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowBackdatedEntry\"\r\n [label]=\"t('allow-backdated-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"autoLockOnApprove\"\r\n [label]=\"t('auto-lock-on-approve')\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"globalWorkingHoursForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"working-hours-card-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"working-hours-card-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"timeZoneId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('global-timezone')\"\r\n [placeholder]=\"t('global-timezone-placeholder')\"\r\n [filter]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"workingDays\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('working-days')\"\r\n [placeholder]=\"t('working-days-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"hoursPerDay\"\r\n [label]=\"t('daily-working-hours')\"\r\n [placeholder]=\"t('daily-working-hours-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-textarea-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"holidaysCsv\"\r\n [label]=\"t('global-holidays')\"\r\n [placeholder]=\"t('global-holidays-placeholder')\"\r\n rows=\"3\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "virtualScroll", "virtualScrollItemSize", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
199
214
  }
200
215
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsTimeSheetSection, decorators: [{
201
216
  type: Component,
@@ -207,11 +222,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
207
222
  NumberField,
208
223
  SelectField,
209
224
  TextareaField,
210
- TextField,
211
225
  ToggleField,
212
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-2 mb-6\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"policyForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"timesheet-policy-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"timesheet-policy-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div\r\n class=\"rounded-lg border border-sky-200 bg-sky-50 px-4 py-3 text-sm text-sky-800\"\r\n >\r\n {{ t(\"timesheet-policy-workflow-note\") }}\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"weekStartDay\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('week-start-day')\"\r\n [placeholder]=\"t('week-start-day-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n formControlName=\"allowedScheduleItemTypes\"\r\n [options]=\"scheduleItemTypeOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'itemType'\"\r\n [label]=\"t('allowed-schedule-item-types')\"\r\n [placeholder]=\"t('allowed-schedule-item-types-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"regularDailyHours\"\r\n [label]=\"t('regular-daily-hours')\"\r\n [placeholder]=\"t('regular-daily-hours-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"maxDailyHours\"\r\n [label]=\"t('max-daily-hours')\"\r\n [placeholder]=\"t('max-daily-hours-placeholder')\"\r\n [min]=\"1\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"pastEntryLockDays\"\r\n [label]=\"t('past-entry-lock-days')\"\r\n [placeholder]=\"t('past-entry-lock-days-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"3650\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"rateSource\"\r\n [options]=\"rateSourceOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('rate-source')\"\r\n [placeholder]=\"t('rate-source-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n <mt-toggle-field\r\n formControlName=\"generationEnabled\"\r\n [label]=\"t('generation-enabled')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"manualGenerationEnabled\"\r\n [label]=\"t('manual-generation-enabled')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowOvertime\"\r\n [label]=\"t('allow-overtime')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"requireOvertimeReason\"\r\n [label]=\"t('require-overtime-reason')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"requireDescription\"\r\n [label]=\"t('require-description')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowFutureEntry\"\r\n [label]=\"t('allow-future-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"assignedItemsOnly\"\r\n [label]=\"t('assigned-items-only')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowZeroHourSubmit\"\r\n [label]=\"t('allow-zero-hour-submit')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"costEnabled\"\r\n [label]=\"t('cost-enabled')\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"globalWorkingHoursForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"global-working-hours-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"global-working-hours-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"timeZoneId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('global-timezone')\"\r\n [placeholder]=\"t('global-timezone-placeholder')\"\r\n [filter]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"workDayStart\"\r\n type=\"time\"\r\n [label]=\"t('work-day-start')\"\r\n [placeholder]=\"t('work-day-start-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"workDayEnd\"\r\n type=\"time\"\r\n [label]=\"t('work-day-end')\"\r\n [placeholder]=\"t('work-day-end-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"workingDays\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('working-days')\"\r\n [placeholder]=\"t('working-days-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-textarea-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"holidaysCsv\"\r\n [label]=\"t('global-holidays')\"\r\n [placeholder]=\"t('global-holidays-placeholder')\"\r\n rows=\"3\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n" }]
213
- }], propDecorators: { policyForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "policyForm", required: true }] }], globalWorkingHoursForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalWorkingHoursForm", required: true }] }], dayOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayOptions", required: false }] }], scheduleItemTypeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "scheduleItemTypeOptions", required: false }] }], rateSourceOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rateSourceOptions", required: false }] }], timezoneOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timezoneOptions", required: false }] }] } });
226
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-2 mb-6\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"policyForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"general-card-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"general-card-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"frequency\"\r\n [options]=\"frequencyOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('frequency')\"\r\n [placeholder]=\"t('frequency-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"maxDailyHours\"\r\n [label]=\"t('max-daily-hours')\"\r\n [placeholder]=\"t('max-daily-hours-placeholder')\"\r\n [min]=\"1\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n [hint]=\"maxDailyBelowDaily() ? t('max-daily-below-daily') : ''\"\r\n />\r\n\r\n <mt-number-field\r\n formControlName=\"submissionDeadlineDays\"\r\n [label]=\"t('submission-deadline-days')\"\r\n [placeholder]=\"t('submission-deadline-days-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"90\"\r\n [required]=\"true\"\r\n [hint]=\"t('submission-deadline-hint')\"\r\n />\r\n </div>\r\n\r\n <div class=\"grid gap-3 md:grid-cols-2\">\r\n <mt-toggle-field\r\n formControlName=\"requireDescription\"\r\n [label]=\"t('require-description')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowFutureEntry\"\r\n [label]=\"t('allow-future-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"allowBackdatedEntry\"\r\n [label]=\"t('allow-backdated-entry')\"\r\n />\r\n <mt-toggle-field\r\n formControlName=\"autoLockOnApprove\"\r\n [label]=\"t('auto-lock-on-approve')\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"globalWorkingHoursForm()\" class=\"space-y-5\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"working-hours-card-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"working-hours-card-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"timeZoneId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('global-timezone')\"\r\n [placeholder]=\"t('global-timezone-placeholder')\"\r\n [filter]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-multi-select-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"workingDays\"\r\n [options]=\"dayOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('working-days')\"\r\n [placeholder]=\"t('working-days-placeholder')\"\r\n [display]=\"'chip'\"\r\n [required]=\"true\"\r\n [showClear]=\"true\"\r\n />\r\n\r\n <mt-number-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"hoursPerDay\"\r\n [label]=\"t('daily-working-hours')\"\r\n [placeholder]=\"t('daily-working-hours-placeholder')\"\r\n [min]=\"0\"\r\n [max]=\"24\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-textarea-field\r\n class=\"md:col-span-2\"\r\n formControlName=\"holidaysCsv\"\r\n [label]=\"t('global-holidays')\"\r\n [placeholder]=\"t('global-holidays-placeholder')\"\r\n rows=\"3\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n" }]
227
+ }], propDecorators: { policyForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "policyForm", required: true }] }], globalWorkingHoursForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalWorkingHoursForm", required: true }] }], dayOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayOptions", required: false }] }], frequencyOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "frequencyOptions", required: false }] }], timezoneOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timezoneOptions", required: false }] }], maxDailyBelowDaily: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDailyBelowDaily", required: false }] }] } });
214
228
 
229
+ /** The settings record General Configuration fields live in. */
230
+ const GENERAL_CONFIGURATION_SETTING_KEY = 'Identity';
215
231
  const FIXED_CURRENCIES = [
216
232
  {
217
233
  code: 'SAR',
@@ -241,6 +257,25 @@ const FIXED_CURRENCIES = [
241
257
  },
242
258
  },
243
259
  ];
260
+ /**
261
+ * Explore landing views, mirroring the app-client explore header switcher
262
+ * (same icons) so the configured default reads as the same choice.
263
+ */
264
+ const EXPLORE_DEFAULT_VIEW_OPTIONS = [
265
+ {
266
+ id: 'cards',
267
+ translationKey: 'explore-default-view-cards',
268
+ icon: 'layout.grid-01',
269
+ },
270
+ {
271
+ id: 'timeline',
272
+ translationKey: 'explore-default-view-timeline',
273
+ icon: 'time.clock',
274
+ },
275
+ ];
276
+ const DEFAULT_GENERAL_CONFIGURATION = {
277
+ defaultExploreView: 'cards',
278
+ };
244
279
  const DEFAULT_DATE_FORMAT_OPTIONS = [
245
280
  {
246
281
  key: 'MM/dd/yyyy',
@@ -303,6 +338,12 @@ const DOTNET_DAY_DEFINITIONS = [
303
338
  { dayNumber: 5, translationKey: 'friday' },
304
339
  { dayNumber: 6, translationKey: 'saturday' },
305
340
  ];
341
+ const TIMESHEET_FREQUENCY_OPTIONS = [
342
+ { id: 'Daily', translationKey: 'frequency-daily' },
343
+ { id: 'Weekly', translationKey: 'frequency-weekly' },
344
+ { id: 'BiWeekly', translationKey: 'frequency-biweekly' },
345
+ { id: 'Monthly', translationKey: 'frequency-monthly' },
346
+ ];
306
347
  const SCHEDULE_ITEM_TYPE_OPTIONS = [
307
348
  { itemType: 'Task', translationKey: 'schedule-item-task' },
308
349
  { itemType: 'Milestone', translationKey: 'schedule-item-milestone' },
@@ -366,6 +407,12 @@ class SystemSettings {
366
407
  },
367
408
  ];
368
409
  form = new FormGroup({
410
+ generalConfiguration: new FormGroup({
411
+ defaultExploreView: new FormControl('cards', {
412
+ nonNullable: true,
413
+ validators: [Validators.required],
414
+ }),
415
+ }),
369
416
  timezone: new FormGroup({
370
417
  regionId: new FormControl(null, Validators.required),
371
418
  dateFormat: new FormControl(null, Validators.required),
@@ -386,53 +433,36 @@ class SystemSettings {
386
433
  port: new FormControl('', { nonNullable: true }),
387
434
  }),
388
435
  timeSheetPolicy: new FormGroup({
389
- weekStartDay: new FormControl(null, Validators.required),
390
- generationEnabled: new FormControl(true, { nonNullable: true }),
391
- manualGenerationEnabled: new FormControl(true, { nonNullable: true }),
392
- regularDailyHours: new FormControl(8, [
393
- Validators.required,
394
- Validators.min(0),
395
- Validators.max(24),
396
- ]),
436
+ frequency: new FormControl('Weekly', Validators.required),
397
437
  maxDailyHours: new FormControl(24, [
398
438
  Validators.required,
399
439
  Validators.min(1),
400
440
  Validators.max(24),
401
441
  ]),
402
- allowOvertime: new FormControl(true, { nonNullable: true }),
403
- requireOvertimeReason: new FormControl(false, { nonNullable: true }),
404
442
  requireDescription: new FormControl(false, { nonNullable: true }),
405
- allowFutureEntry: new FormControl(true, { nonNullable: true }),
406
- pastEntryLockDays: new FormControl(null, [
443
+ allowFutureEntry: new FormControl(false, { nonNullable: true }),
444
+ allowBackdatedEntry: new FormControl(true, { nonNullable: true }),
445
+ autoLockOnApprove: new FormControl(true, { nonNullable: true }),
446
+ submissionDeadlineDays: new FormControl(3, [
447
+ Validators.required,
407
448
  Validators.min(0),
408
- Validators.max(3650),
449
+ Validators.max(90),
409
450
  ]),
410
- allowedScheduleItemTypes: new FormControl(['Deliverable'], {
411
- nonNullable: true,
412
- validators: [Validators.required],
413
- }),
414
- assignedItemsOnly: new FormControl(false, { nonNullable: true }),
415
- allowZeroHourSubmit: new FormControl(true, { nonNullable: true }),
416
- costEnabled: new FormControl(true, { nonNullable: true }),
417
- rateSource: new FormControl('UserHourlyRate', Validators.required),
418
451
  }),
419
452
  globalWorkingHours: new FormGroup({
420
453
  timeZoneId: new FormControl(null, Validators.required),
421
- workDayStart: new FormControl('08:00', {
422
- nonNullable: true,
423
- validators: [Validators.required],
424
- }),
425
- workDayEnd: new FormControl('16:00', {
426
- nonNullable: true,
427
- validators: [Validators.required],
428
- }),
429
454
  workingDays: new FormControl([0, 1, 2, 3, 4], {
430
455
  nonNullable: true,
431
456
  validators: [Validators.required],
432
457
  }),
458
+ hoursPerDay: new FormControl(8, [
459
+ Validators.required,
460
+ Validators.min(0),
461
+ Validators.max(24),
462
+ ]),
433
463
  holidaysCsv: new FormControl('', { nonNullable: true }),
434
464
  }),
435
- });
465
+ }, maxDailyHoursGteHoursPerDay);
436
466
  settings = signal(null, ...(ngDevMode ? [{ debugName: "settings" }] : /* istanbul ignore next */ []));
437
467
  settingsLoading = signal(false, ...(ngDevMode ? [{ debugName: "settingsLoading" }] : /* istanbul ignore next */ []));
438
468
  settingsError = signal(null, ...(ngDevMode ? [{ debugName: "settingsError" }] : /* istanbul ignore next */ []));
@@ -463,6 +493,12 @@ class SystemSettings {
463
493
  formValue = toSignal(this.form.valueChanges, {
464
494
  initialValue: this.form.getRawValue(),
465
495
  });
496
+ /**
497
+ * The `Identity` record. It is shared with `@masterteam/brand-display`, which
498
+ * owns every other field in it — we only read/write the General Configuration
499
+ * slice and must preserve the rest verbatim.
500
+ */
501
+ generalConfigurationSetting = computed(() => this.findSettingByKey(GENERAL_CONFIGURATION_SETTING_KEY), ...(ngDevMode ? [{ debugName: "generalConfigurationSetting" }] : /* istanbul ignore next */ []));
466
502
  holidaysSetting = computed(() => this.findSettingByKey('Holidays'), ...(ngDevMode ? [{ debugName: "holidaysSetting" }] : /* istanbul ignore next */ []));
467
503
  timezoneSetting = computed(() => this.findSettingByKey('Timezone'), ...(ngDevMode ? [{ debugName: "timezoneSetting" }] : /* istanbul ignore next */ []));
468
504
  currencySetting = computed(() => this.findSettingByKey('Currency'), ...(ngDevMode ? [{ debugName: "currencySetting" }] : /* istanbul ignore next */ []));
@@ -510,21 +546,21 @@ class SystemSettings {
510
546
  name: this.transloco.translate(`system-settings.${day.translationKey}`),
511
547
  }));
512
548
  }, ...(ngDevMode ? [{ debugName: "dotnetDayOptions" }] : /* istanbul ignore next */ []));
513
- scheduleItemTypeOptions = computed(() => {
549
+ exploreDefaultViewOptions = computed(() => {
514
550
  this.activeLang();
515
- return SCHEDULE_ITEM_TYPE_OPTIONS.map((item) => ({
516
- id: item.itemType,
517
- itemType: item.itemType,
518
- name: this.transloco.translate(`system-settings.${item.translationKey}`),
551
+ return EXPLORE_DEFAULT_VIEW_OPTIONS.map((option) => ({
552
+ id: option.id,
553
+ name: this.transloco.translate(`system-settings.${option.translationKey}`),
554
+ icon: option.icon,
519
555
  }));
520
- }, ...(ngDevMode ? [{ debugName: "scheduleItemTypeOptions" }] : /* istanbul ignore next */ []));
521
- rateSourceOptions = computed(() => {
556
+ }, ...(ngDevMode ? [{ debugName: "exploreDefaultViewOptions" }] : /* istanbul ignore next */ []));
557
+ frequencyOptions = computed(() => {
522
558
  this.activeLang();
523
- return RATE_SOURCE_OPTIONS.map((item) => ({
559
+ return TIMESHEET_FREQUENCY_OPTIONS.map((item) => ({
524
560
  id: item.id,
525
561
  name: this.transloco.translate(`system-settings.${item.translationKey}`),
526
562
  }));
527
- }, ...(ngDevMode ? [{ debugName: "rateSourceOptions" }] : /* istanbul ignore next */ []));
563
+ }, ...(ngDevMode ? [{ debugName: "frequencyOptions" }] : /* istanbul ignore next */ []));
528
564
  isReady = computed(() => this.hydrationVersion() !== null && this.initialSnapshot() !== null, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
529
565
  isLoading = computed(() => this.settingsLoading() || this.timezonesLoading() || !this.isReady(), ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
530
566
  hasChanges = computed(() => {
@@ -538,7 +574,8 @@ class SystemSettings {
538
574
  if (!current) {
539
575
  return false;
540
576
  }
541
- return (!this.areEqual(initial.holidays, current.holidays) ||
577
+ return (!this.areEqual(initial.generalConfiguration, current.generalConfiguration) ||
578
+ !this.areEqual(initial.holidays, current.holidays) ||
542
579
  !this.areEqual(initial.timezone, current.timezone) ||
543
580
  !this.areEqual(initial.currency, current.currency) ||
544
581
  !this.areEqual(initial.weekend, current.weekend) ||
@@ -572,7 +609,8 @@ class SystemSettings {
572
609
  if (version === this.hydrationVersion()) {
573
610
  return;
574
611
  }
575
- this.hydrateForm(this.holidaysSetting() ?? this.createFallbackSetting('Holidays'), this.timezoneSetting() ?? this.createFallbackSetting('Timezone'), this.currencySetting() ?? this.createFallbackSetting('Currency'), this.weekendSetting() ?? this.createFallbackSetting('Weekend'), this.smtpSetting() ?? this.createFallbackSetting('SMTP'), this.timeSheetPolicySetting() ??
612
+ this.hydrateForm(this.generalConfigurationSetting() ??
613
+ this.createFallbackSetting(GENERAL_CONFIGURATION_SETTING_KEY), this.holidaysSetting() ?? this.createFallbackSetting('Holidays'), this.timezoneSetting() ?? this.createFallbackSetting('Timezone'), this.currencySetting() ?? this.createFallbackSetting('Currency'), this.weekendSetting() ?? this.createFallbackSetting('Weekend'), this.smtpSetting() ?? this.createFallbackSetting('SMTP'), this.timeSheetPolicySetting() ??
576
614
  this.createFallbackSetting('TimeSheetPolicy'), this.globalWorkingHoursSetting() ??
577
615
  this.createFallbackSetting('GlobalWorkingHours'));
578
616
  this.hydrationVersion.set(version);
@@ -642,6 +680,18 @@ class SystemSettings {
642
680
  return;
643
681
  }
644
682
  const values = [];
683
+ if (!this.areEqual(initialSnapshot.generalConfiguration, nextSnapshot.generalConfiguration)) {
684
+ // `Identity` is shared with brand-display and is saved by full
685
+ // replacement, so merge our slice onto the record as last loaded instead
686
+ // of sending it alone — sending only our fields would wipe the branding.
687
+ values.push({
688
+ key: GENERAL_CONFIGURATION_SETTING_KEY,
689
+ value: {
690
+ ...this.getIdentityRecord(),
691
+ ...nextSnapshot.generalConfiguration,
692
+ },
693
+ });
694
+ }
645
695
  if (!this.areEqual(initialSnapshot.holidays, nextSnapshot.holidays)) {
646
696
  values.push({
647
697
  key: 'Holidays',
@@ -748,15 +798,19 @@ class SystemSettings {
748
798
  },
749
799
  });
750
800
  }
751
- hydrateForm(holidaysSetting, timezoneSetting, currencySetting, weekendSetting, smtpSetting, timeSheetPolicySetting, globalWorkingHoursSetting) {
801
+ hydrateForm(generalConfigurationSetting, holidaysSetting, timezoneSetting, currencySetting, weekendSetting, smtpSetting, timeSheetPolicySetting, globalWorkingHoursSetting) {
802
+ const generalConfiguration = this.normalizeGeneralConfigurationSnapshot(this.extractGeneralConfigurationValue(generalConfigurationSetting));
752
803
  const holidays = this.extractHolidaysValue(holidaysSetting);
753
804
  const timezone = this.normalizeTimezoneSnapshot(this.extractTimezoneValue(timezoneSetting));
754
805
  const currency = this.normalizeCurrencySnapshot(this.extractCurrencyValue(currencySetting));
755
806
  const weekend = this.normalizeWeekendSnapshot(this.extractWeekendValue(weekendSetting));
756
807
  const smtp = this.normalizeSmtpSnapshot(this.extractSmtpValue(smtpSetting));
757
- const timeSheetPolicy = this.normalizeTimeSheetPolicySnapshot(this.extractTimeSheetPolicyValue(timeSheetPolicySetting));
758
808
  const globalWorkingHours = this.normalizeGlobalWorkingHoursSnapshot(this.extractGlobalWorkingHoursValue(globalWorkingHoursSetting));
809
+ const timeSheetPolicy = this.normalizeTimeSheetPolicySnapshot(this.extractTimeSheetPolicyValue(timeSheetPolicySetting), globalWorkingHours.hoursPerDay);
759
810
  this.holidayItems.set(holidays.data);
811
+ this.form.controls.generalConfiguration.setValue({
812
+ defaultExploreView: generalConfiguration.defaultExploreView,
813
+ });
760
814
  this.form.controls.timezone.setValue({
761
815
  regionId: timezone.region?.id ?? null,
762
816
  dateFormat: timezone.dateFormat,
@@ -777,32 +831,24 @@ class SystemSettings {
777
831
  port: smtp.port === null ? '' : String(smtp.port),
778
832
  });
779
833
  this.form.controls.timeSheetPolicy.setValue({
780
- weekStartDay: timeSheetPolicy.weekStartDay,
781
- generationEnabled: timeSheetPolicy.generationEnabled,
782
- manualGenerationEnabled: timeSheetPolicy.manualGenerationEnabled,
783
- regularDailyHours: timeSheetPolicy.regularDailyHours,
834
+ frequency: timeSheetPolicy.frequency,
784
835
  maxDailyHours: timeSheetPolicy.maxDailyHours,
785
- allowOvertime: timeSheetPolicy.allowOvertime,
786
- requireOvertimeReason: timeSheetPolicy.requireOvertimeReason,
787
836
  requireDescription: timeSheetPolicy.requireDescription,
788
837
  allowFutureEntry: timeSheetPolicy.allowFutureEntry,
789
- pastEntryLockDays: timeSheetPolicy.pastEntryLockDays,
790
- allowedScheduleItemTypes: timeSheetPolicy.allowedScheduleItemTypes,
791
- assignedItemsOnly: timeSheetPolicy.assignedItemsOnly,
792
- allowZeroHourSubmit: timeSheetPolicy.allowZeroHourSubmit,
793
- costEnabled: timeSheetPolicy.costEnabled,
794
- rateSource: timeSheetPolicy.rateSource,
838
+ allowBackdatedEntry: timeSheetPolicy.allowBackdatedEntry,
839
+ autoLockOnApprove: timeSheetPolicy.autoLockOnApprove,
840
+ submissionDeadlineDays: timeSheetPolicy.submissionDeadlineDays,
795
841
  });
796
842
  this.form.controls.globalWorkingHours.setValue({
797
843
  timeZoneId: globalWorkingHours.timeZoneId,
798
- workDayStart: minutesToTime(globalWorkingHours.workDayStartMinute),
799
- workDayEnd: minutesToTime(globalWorkingHours.workDayEndMinute),
800
844
  workingDays: globalWorkingHours.workingDays,
845
+ hoursPerDay: globalWorkingHours.hoursPerDay,
801
846
  holidaysCsv: globalWorkingHours.holidays.join(', '),
802
847
  });
803
848
  this.form.markAsPristine();
804
849
  this.form.markAsUntouched();
805
850
  this.initialSnapshot.set({
851
+ generalConfiguration,
806
852
  holidays,
807
853
  timezone,
808
854
  currency,
@@ -819,6 +865,7 @@ class SystemSettings {
819
865
  return null;
820
866
  }
821
867
  return {
868
+ generalConfiguration: this.buildGeneralConfigurationValue(),
822
869
  holidays: {
823
870
  data: this.holidayItems().map((item) => ({
824
871
  label: item.label.trim(),
@@ -869,6 +916,21 @@ class SystemSettings {
869
916
  format: currencyForm.format,
870
917
  };
871
918
  }
919
+ /**
920
+ * The `Identity` value exactly as last returned by the API (or written by a
921
+ * previous save in this session), used as the base every save merges onto so
922
+ * branding fields this page does not model survive round-trips.
923
+ */
924
+ getIdentityRecord() {
925
+ const value = this.generalConfigurationSetting()?.value;
926
+ return isRecord(value) ? value : {};
927
+ }
928
+ buildGeneralConfigurationValue() {
929
+ return {
930
+ defaultExploreView: normalizeExploreDefaultView(this.form.controls.generalConfiguration.controls.defaultExploreView
931
+ .value),
932
+ };
933
+ }
872
934
  buildWeekendValue() {
873
935
  return {
874
936
  days: normalizeWeekendDays(this.form.controls.weekend.controls.days.value),
@@ -886,35 +948,23 @@ class SystemSettings {
886
948
  }
887
949
  buildTimeSheetPolicyValue() {
888
950
  const policyForm = this.form.controls.timeSheetPolicy.getRawValue();
951
+ const hoursPerDay = clampNumber(this.form.controls.globalWorkingHours.controls.hoursPerDay.value ?? 8, 0, 24);
889
952
  return {
890
- weekStartDay: policyForm.weekStartDay ?? 0,
891
- generationEnabled: policyForm.generationEnabled,
892
- manualGenerationEnabled: policyForm.manualGenerationEnabled,
893
- regularDailyHours: policyForm.regularDailyHours ?? 8,
894
- maxDailyHours: policyForm.maxDailyHours ?? 24,
895
- allowOvertime: policyForm.allowOvertime,
896
- requireOvertimeReason: policyForm.allowOvertime
897
- ? policyForm.requireOvertimeReason
898
- : false,
953
+ frequency: normalizeFrequency(policyForm.frequency),
954
+ maxDailyHours: Math.max(hoursPerDay, clampNumber(policyForm.maxDailyHours ?? 24, 1, 24)),
899
955
  requireDescription: policyForm.requireDescription,
900
956
  allowFutureEntry: policyForm.allowFutureEntry,
901
- pastEntryLockDays: policyForm.pastEntryLockDays,
902
- allowedScheduleItemTypes: policyForm.allowedScheduleItemTypes,
903
- assignedItemsOnly: policyForm.assignedItemsOnly,
904
- allowZeroHourSubmit: policyForm.allowZeroHourSubmit,
905
- costEnabled: policyForm.costEnabled,
906
- rateSource: policyForm.costEnabled
907
- ? (policyForm.rateSource ?? 'UserHourlyRate')
908
- : 'None',
957
+ allowBackdatedEntry: policyForm.allowBackdatedEntry,
958
+ autoLockOnApprove: policyForm.autoLockOnApprove,
959
+ submissionDeadlineDays: clampNumber(policyForm.submissionDeadlineDays ?? 0, 0, 90),
909
960
  };
910
961
  }
911
962
  buildGlobalWorkingHoursValue() {
912
963
  const globalForm = this.form.controls.globalWorkingHours.getRawValue();
913
964
  return {
914
965
  timeZoneId: globalForm.timeZoneId ?? 'UTC',
915
- workDayStartMinute: timeToMinutes(globalForm.workDayStart),
916
- workDayEndMinute: timeToMinutes(globalForm.workDayEnd),
917
966
  workingDays: normalizeDotnetDays(globalForm.workingDays),
967
+ hoursPerDay: clampNumber(globalForm.hoursPerDay ?? 8, 0, 24),
918
968
  holidays: parseCsv(globalForm.holidaysCsv),
919
969
  };
920
970
  }
@@ -922,6 +972,15 @@ class SystemSettings {
922
972
  const normalizedKey = key.trim().toLowerCase();
923
973
  return (this.settings()?.find((setting) => setting.key.trim().toLowerCase() === normalizedKey) ?? null);
924
974
  }
975
+ extractGeneralConfigurationValue(setting) {
976
+ if (!isRecord(setting.value)) {
977
+ return { ...DEFAULT_GENERAL_CONFIGURATION };
978
+ }
979
+ return {
980
+ defaultExploreView: normalizeExploreDefaultView(setting.value['defaultExploreView'] ??
981
+ setting.value['DefaultExploreView']),
982
+ };
983
+ }
925
984
  extractHolidaysValue(setting) {
926
985
  if (!isRecord(setting.value)) {
927
986
  return { data: [] };
@@ -988,47 +1047,36 @@ class SystemSettings {
988
1047
  if (!isRecord(setting.value)) {
989
1048
  return this.getDefaultTimeSheetPolicyValue();
990
1049
  }
1050
+ const value = setting.value;
991
1051
  const defaults = this.getDefaultTimeSheetPolicyValue();
992
1052
  return {
993
- weekStartDay: getNumber(setting.value['weekStartDay']) ?? defaults.weekStartDay,
994
- generationEnabled: getBoolean(setting.value['generationEnabled']) ??
995
- defaults.generationEnabled,
996
- manualGenerationEnabled: getBoolean(setting.value['manualGenerationEnabled']) ??
997
- defaults.manualGenerationEnabled,
998
- regularDailyHours: getNumber(setting.value['regularDailyHours']) ??
999
- defaults.regularDailyHours,
1000
- maxDailyHours: getNumber(setting.value['maxDailyHours']) ?? defaults.maxDailyHours,
1001
- allowOvertime: getBoolean(setting.value['allowOvertime']) ?? defaults.allowOvertime,
1002
- requireOvertimeReason: getBoolean(setting.value['requireOvertimeReason']) ??
1003
- defaults.requireOvertimeReason,
1004
- requireDescription: getBoolean(setting.value['requireDescription']) ??
1005
- defaults.requireDescription,
1006
- allowFutureEntry: getBoolean(setting.value['allowFutureEntry']) ??
1053
+ frequency: normalizeFrequency(value['frequency'] ?? value['Frequency']),
1054
+ maxDailyHours: getNumber(value['maxDailyHours'] ?? value['MaxDailyHours']) ??
1055
+ defaults.maxDailyHours,
1056
+ requireDescription: getBoolean(value['requireDescription'] ?? value['RequireDescription']) ?? defaults.requireDescription,
1057
+ allowFutureEntry: getBoolean(value['allowFutureEntry'] ?? value['AllowFutureEntry']) ??
1007
1058
  defaults.allowFutureEntry,
1008
- pastEntryLockDays: getNullableNumber(setting.value['pastEntryLockDays']),
1009
- allowedScheduleItemTypes: getStringArray(setting.value['allowedScheduleItemTypes']) ??
1010
- defaults.allowedScheduleItemTypes,
1011
- assignedItemsOnly: getBoolean(setting.value['assignedItemsOnly']) ??
1012
- defaults.assignedItemsOnly,
1013
- allowZeroHourSubmit: getBoolean(setting.value['allowZeroHourSubmit']) ??
1014
- defaults.allowZeroHourSubmit,
1015
- costEnabled: getBoolean(setting.value['costEnabled']) ?? defaults.costEnabled,
1016
- rateSource: getString(setting.value['rateSource']) ?? defaults.rateSource,
1059
+ allowBackdatedEntry: getBoolean(value['allowBackdatedEntry'] ?? value['AllowBackdatedEntry']) ?? defaults.allowBackdatedEntry,
1060
+ autoLockOnApprove: getBoolean(value['autoLockOnApprove'] ?? value['AutoLockOnApprove']) ??
1061
+ defaults.autoLockOnApprove,
1062
+ submissionDeadlineDays: getNumber(value['submissionDeadlineDays'] ?? value['SubmissionDeadlineDays']) ?? defaults.submissionDeadlineDays,
1017
1063
  };
1018
1064
  }
1019
1065
  extractGlobalWorkingHoursValue(setting) {
1020
1066
  if (!isRecord(setting.value)) {
1021
1067
  return this.getDefaultGlobalWorkingHoursValue();
1022
1068
  }
1069
+ const value = setting.value;
1023
1070
  const defaults = this.getDefaultGlobalWorkingHoursValue();
1024
1071
  return {
1025
- timeZoneId: getString(setting.value['timeZoneId']) ?? defaults.timeZoneId,
1026
- workDayStartMinute: getNumber(setting.value['workDayStartMinute']) ??
1027
- defaults.workDayStartMinute,
1028
- workDayEndMinute: getNumber(setting.value['workDayEndMinute']) ??
1029
- defaults.workDayEndMinute,
1030
- workingDays: getNumberArray(setting.value['workingDays']) ?? defaults.workingDays,
1031
- holidays: getStringArray(setting.value['holidays']) ?? defaults.holidays,
1072
+ timeZoneId: getString(value['timeZoneId'] ?? value['TimeZoneId']) ??
1073
+ defaults.timeZoneId,
1074
+ workingDays: getNumberArray(value['workingDays'] ?? value['WorkingDays']) ??
1075
+ defaults.workingDays,
1076
+ hoursPerDay: getNumber(value['hoursPerDay'] ?? value['HoursPerDay']) ??
1077
+ defaults.hoursPerDay,
1078
+ holidays: getStringArray(value['holidays'] ?? value['Holidays']) ??
1079
+ defaults.holidays,
1032
1080
  };
1033
1081
  }
1034
1082
  normalizeHolidayItem(value) {
@@ -1091,6 +1139,11 @@ class SystemSettings {
1091
1139
  ar: getString(value['ar']) ?? FIXED_CURRENCIES[0].unit.ar,
1092
1140
  };
1093
1141
  }
1142
+ normalizeGeneralConfigurationSnapshot(value) {
1143
+ return {
1144
+ defaultExploreView: normalizeExploreDefaultView(value.defaultExploreView),
1145
+ };
1146
+ }
1094
1147
  normalizeTimezoneSnapshot(value) {
1095
1148
  const defaults = this.getDefaultTimezoneValue();
1096
1149
  return {
@@ -1124,38 +1177,35 @@ class SystemSettings {
1124
1177
  port: value.port,
1125
1178
  };
1126
1179
  }
1127
- normalizeTimeSheetPolicySnapshot(value) {
1128
- const defaults = this.getDefaultTimeSheetPolicyValue();
1129
- const regularDailyHours = clampNumber(value.regularDailyHours, 0, 24);
1130
- const maxDailyHours = Math.max(regularDailyHours, clampNumber(value.maxDailyHours, 1, 24));
1131
- const allowedScheduleItemTypes = value.allowedScheduleItemTypes.length
1132
- ? value.allowedScheduleItemTypes
1133
- : defaults.allowedScheduleItemTypes;
1180
+ normalizeTimeSheetPolicySnapshot(value, hoursPerDay) {
1134
1181
  return {
1135
- ...defaults,
1136
- ...value,
1137
- weekStartDay: clampNumber(value.weekStartDay, 0, 6),
1138
- regularDailyHours,
1139
- maxDailyHours,
1140
- pastEntryLockDays: value.pastEntryLockDays === null
1141
- ? null
1142
- : clampNumber(value.pastEntryLockDays, 0, 3650),
1143
- allowedScheduleItemTypes,
1144
- rateSource: value.rateSource || defaults.rateSource,
1182
+ frequency: normalizeFrequency(value.frequency),
1183
+ maxDailyHours: Math.max(clampNumber(hoursPerDay, 0, 24), clampNumber(value.maxDailyHours, 1, 24)),
1184
+ requireDescription: value.requireDescription,
1185
+ allowFutureEntry: value.allowFutureEntry,
1186
+ allowBackdatedEntry: value.allowBackdatedEntry,
1187
+ autoLockOnApprove: value.autoLockOnApprove,
1188
+ submissionDeadlineDays: clampNumber(value.submissionDeadlineDays, 0, 90),
1145
1189
  };
1146
1190
  }
1147
1191
  normalizeGlobalWorkingHoursSnapshot(value) {
1148
1192
  const defaults = this.getDefaultGlobalWorkingHoursValue();
1149
1193
  return {
1150
1194
  timeZoneId: value.timeZoneId || defaults.timeZoneId,
1151
- workDayStartMinute: clampNumber(value.workDayStartMinute, 0, 1439),
1152
- workDayEndMinute: clampNumber(value.workDayEndMinute, 1, 1440),
1153
1195
  workingDays: normalizeDotnetDays(value.workingDays),
1196
+ hoursPerDay: clampNumber(value.hoursPerDay, 0, 24),
1154
1197
  holidays: value.holidays,
1155
1198
  };
1156
1199
  }
1157
1200
  createFallbackSetting(key) {
1158
1201
  switch (key) {
1202
+ case 'Identity':
1203
+ return {
1204
+ key,
1205
+ label: key,
1206
+ description: key,
1207
+ value: { ...DEFAULT_GENERAL_CONFIGURATION },
1208
+ };
1159
1209
  case 'Holidays':
1160
1210
  return { key, label: key, description: key, value: { data: [] } };
1161
1211
  case 'Timezone':
@@ -1235,29 +1285,20 @@ class SystemSettings {
1235
1285
  }
1236
1286
  getDefaultTimeSheetPolicyValue() {
1237
1287
  return {
1238
- weekStartDay: 0,
1239
- generationEnabled: true,
1240
- manualGenerationEnabled: true,
1241
- regularDailyHours: 8,
1288
+ frequency: 'Weekly',
1242
1289
  maxDailyHours: 24,
1243
- allowOvertime: true,
1244
- requireOvertimeReason: false,
1245
1290
  requireDescription: false,
1246
- allowFutureEntry: true,
1247
- pastEntryLockDays: null,
1248
- allowedScheduleItemTypes: ['Deliverable'],
1249
- assignedItemsOnly: false,
1250
- allowZeroHourSubmit: true,
1251
- costEnabled: true,
1252
- rateSource: 'UserHourlyRate',
1291
+ allowFutureEntry: false,
1292
+ allowBackdatedEntry: true,
1293
+ autoLockOnApprove: true,
1294
+ submissionDeadlineDays: 3,
1253
1295
  };
1254
1296
  }
1255
1297
  getDefaultGlobalWorkingHoursValue() {
1256
1298
  return {
1257
1299
  timeZoneId: this.timezones()[0]?.id ?? 'UTC',
1258
- workDayStartMinute: 480,
1259
- workDayEndMinute: 960,
1260
1300
  workingDays: [0, 1, 2, 3, 4],
1301
+ hoursPerDay: 8,
1261
1302
  holidays: [],
1262
1303
  };
1263
1304
  }
@@ -1375,7 +1416,7 @@ class SystemSettings {
1375
1416
  return JSON.stringify(left) === JSON.stringify(right);
1376
1417
  }
1377
1418
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettings, deps: [], target: i0.ɵɵFactoryTarget.Component });
1378
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SystemSettings, isStandalone: true, selector: "mt-system-settings", inputs: { apiBasePath: { classPropertyName: "apiBasePath", publicName: "apiBasePath", isSignal: true, isRequired: false, transformFunction: null }, backRoute: { classPropertyName: "backRoute", publicName: "backRoute", isSignal: true, isRequired: false, transformFunction: null }, formatSchema: { classPropertyName: "formatSchema", publicName: "formatSchema", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n [avatarStyle]=\"{\r\n '--p-avatar-background': 'var(--p-emerald-100)',\r\n '--p-avatar-color': 'var(--p-emerald-700)',\r\n }\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-3\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-end md:justify-between\"\r\n >\r\n <div>\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <mt-breadcrumb\r\n [items]=\"breadcrumbItems\"\r\n [styleClass]=\"'flex justify-start mx-1'\"\r\n />\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-01\"\r\n [tooltip]=\"t('save-tooltip')\"\r\n [badge]=\"hasChanges() ? '!' : ''\"\r\n badgeSeverity=\"warn\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"space-y-4\">\r\n <p-skeleton width=\"100%\" height=\"12rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"18rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"14rem\" borderRadius=\"0.75rem\" />\r\n </div>\r\n } @else {\r\n <!--\r\n BE/HTTP errors (timezonesError, settingsError, updateError) are already\r\n surfaced as toasts by the HTTP interceptor, so they are intentionally\r\n not rendered as top-of-page banners here to avoid duplicate messaging.\r\n -->\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-timesheet-section\r\n [policyForm]=\"form.controls.timeSheetPolicy\"\r\n [globalWorkingHoursForm]=\"form.controls.globalWorkingHours\"\r\n [dayOptions]=\"dotnetDayOptions()\"\r\n [scheduleItemTypeOptions]=\"scheduleItemTypeOptions()\"\r\n [rateSourceOptions]=\"rateSourceOptions()\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Breadcrumb, selector: "mt-breadcrumb", inputs: ["items", "styleClass"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: SystemSettingsHolidaysSection, selector: "mt-system-settings-holidays-section", inputs: ["holidays"], outputs: ["addHoliday", "editHoliday", "deleteHoliday"] }, { kind: "component", type: SystemSettingsGeneralSection, selector: "mt-system-settings-general-section", inputs: ["timezoneForm", "currencyForm", "weekendForm", "timezoneOptions", "dateFormatOptions", "timeFormatOptions", "currencyOptions", "currencyFormatOptions", "weekendOptions"] }, { kind: "component", type: SystemSettingsSmtpSection, selector: "mt-system-settings-smtp-section", inputs: ["smtpForm"] }, { kind: "component", type: SystemSettingsTimeSheetSection, selector: "mt-system-settings-timesheet-section", inputs: ["policyForm", "globalWorkingHoursForm", "dayOptions", "scheduleItemTypeOptions", "rateSourceOptions", "timezoneOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1419
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SystemSettings, isStandalone: true, selector: "mt-system-settings", inputs: { apiBasePath: { classPropertyName: "apiBasePath", publicName: "apiBasePath", isSignal: true, isRequired: false, transformFunction: null }, backRoute: { classPropertyName: "backRoute", publicName: "backRoute", isSignal: true, isRequired: false, transformFunction: null }, formatSchema: { classPropertyName: "formatSchema", publicName: "formatSchema", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n [avatarStyle]=\"{\r\n '--p-avatar-background': 'var(--p-emerald-100)',\r\n '--p-avatar-color': 'var(--p-emerald-700)',\r\n }\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-3\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-end md:justify-between\"\r\n >\r\n <div>\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <mt-breadcrumb\r\n [items]=\"breadcrumbItems\"\r\n [styleClass]=\"'flex justify-start mx-1'\"\r\n />\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-01\"\r\n [tooltip]=\"t('save-tooltip')\"\r\n [badge]=\"hasChanges() ? '!' : ''\"\r\n badgeSeverity=\"warn\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"space-y-4\">\r\n <p-skeleton width=\"100%\" height=\"12rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"18rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"14rem\" borderRadius=\"0.75rem\" />\r\n </div>\r\n } @else {\r\n <!--\r\n BE/HTTP errors (timezonesError, settingsError, updateError) are already\r\n surfaced as toasts by the HTTP interceptor, so they are intentionally\r\n not rendered as top-of-page banners here to avoid duplicate messaging.\r\n -->\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-config-section\r\n [generalConfigurationForm]=\"form.controls.generalConfiguration\"\r\n [exploreDefaultViewOptions]=\"exploreDefaultViewOptions()\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-timesheet-section\r\n [policyForm]=\"form.controls.timeSheetPolicy\"\r\n [globalWorkingHoursForm]=\"form.controls.globalWorkingHours\"\r\n [dayOptions]=\"dotnetDayOptions()\"\r\n [frequencyOptions]=\"frequencyOptions()\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [maxDailyBelowDaily]=\"form.errors?.['maxDailyBelowDaily'] ?? false\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Breadcrumb, selector: "mt-breadcrumb", inputs: ["items", "styleClass"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: SystemSettingsHolidaysSection, selector: "mt-system-settings-holidays-section", inputs: ["holidays"], outputs: ["addHoliday", "editHoliday", "deleteHoliday"] }, { kind: "component", type: SystemSettingsGeneralConfigSection, selector: "mt-system-settings-general-config-section", inputs: ["generalConfigurationForm", "exploreDefaultViewOptions"] }, { kind: "component", type: SystemSettingsGeneralSection, selector: "mt-system-settings-general-section", inputs: ["timezoneForm", "currencyForm", "weekendForm", "timezoneOptions", "dateFormatOptions", "timeFormatOptions", "currencyOptions", "currencyFormatOptions", "weekendOptions"] }, { kind: "component", type: SystemSettingsSmtpSection, selector: "mt-system-settings-smtp-section", inputs: ["smtpForm"] }, { kind: "component", type: SystemSettingsTimeSheetSection, selector: "mt-system-settings-timesheet-section", inputs: ["policyForm", "globalWorkingHoursForm", "dayOptions", "frequencyOptions", "timezoneOptions", "maxDailyBelowDaily"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1379
1420
  }
1380
1421
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettings, decorators: [{
1381
1422
  type: Component,
@@ -1388,10 +1429,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1388
1429
  Breadcrumb,
1389
1430
  SkeletonModule,
1390
1431
  SystemSettingsHolidaysSection,
1432
+ SystemSettingsGeneralConfigSection,
1391
1433
  SystemSettingsGeneralSection,
1392
1434
  SystemSettingsSmtpSection,
1393
1435
  SystemSettingsTimeSheetSection,
1394
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n [avatarStyle]=\"{\r\n '--p-avatar-background': 'var(--p-emerald-100)',\r\n '--p-avatar-color': 'var(--p-emerald-700)',\r\n }\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-3\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-end md:justify-between\"\r\n >\r\n <div>\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <mt-breadcrumb\r\n [items]=\"breadcrumbItems\"\r\n [styleClass]=\"'flex justify-start mx-1'\"\r\n />\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-01\"\r\n [tooltip]=\"t('save-tooltip')\"\r\n [badge]=\"hasChanges() ? '!' : ''\"\r\n badgeSeverity=\"warn\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"space-y-4\">\r\n <p-skeleton width=\"100%\" height=\"12rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"18rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"14rem\" borderRadius=\"0.75rem\" />\r\n </div>\r\n } @else {\r\n <!--\r\n BE/HTTP errors (timezonesError, settingsError, updateError) are already\r\n surfaced as toasts by the HTTP interceptor, so they are intentionally\r\n not rendered as top-of-page banners here to avoid duplicate messaging.\r\n -->\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-timesheet-section\r\n [policyForm]=\"form.controls.timeSheetPolicy\"\r\n [globalWorkingHoursForm]=\"form.controls.globalWorkingHours\"\r\n [dayOptions]=\"dotnetDayOptions()\"\r\n [scheduleItemTypeOptions]=\"scheduleItemTypeOptions()\"\r\n [rateSourceOptions]=\"rateSourceOptions()\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
1436
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n [avatarStyle]=\"{\r\n '--p-avatar-background': 'var(--p-emerald-100)',\r\n '--p-avatar-color': 'var(--p-emerald-700)',\r\n }\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-3\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-end md:justify-between\"\r\n >\r\n <div>\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <mt-breadcrumb\r\n [items]=\"breadcrumbItems\"\r\n [styleClass]=\"'flex justify-start mx-1'\"\r\n />\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n icon=\"general.save-01\"\r\n [tooltip]=\"t('save-tooltip')\"\r\n [badge]=\"hasChanges() ? '!' : ''\"\r\n badgeSeverity=\"warn\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"space-y-4\">\r\n <p-skeleton width=\"100%\" height=\"12rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"18rem\" borderRadius=\"0.75rem\" />\r\n <p-skeleton width=\"100%\" height=\"14rem\" borderRadius=\"0.75rem\" />\r\n </div>\r\n } @else {\r\n <!--\r\n BE/HTTP errors (timezonesError, settingsError, updateError) are already\r\n surfaced as toasts by the HTTP interceptor, so they are intentionally\r\n not rendered as top-of-page banners here to avoid duplicate messaging.\r\n -->\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-config-section\r\n [generalConfigurationForm]=\"form.controls.generalConfiguration\"\r\n [exploreDefaultViewOptions]=\"exploreDefaultViewOptions()\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-timesheet-section\r\n [policyForm]=\"form.controls.timeSheetPolicy\"\r\n [globalWorkingHoursForm]=\"form.controls.globalWorkingHours\"\r\n [dayOptions]=\"dotnetDayOptions()\"\r\n [frequencyOptions]=\"frequencyOptions()\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [maxDailyBelowDaily]=\"form.errors?.['maxDailyBelowDaily'] ?? false\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
1395
1437
  }], ctorParameters: () => [], propDecorators: { apiBasePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiBasePath", required: false }] }], backRoute: [{ type: i0.Input, args: [{ isSignal: true, alias: "backRoute", required: false }] }], formatSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatSchema", required: false }] }] } });
1396
1438
  function isRecord(value) {
1397
1439
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -1461,6 +1503,11 @@ function parsePort(value) {
1461
1503
  const parsedValue = Number(normalizedValue);
1462
1504
  return Number.isNaN(parsedValue) ? null : parsedValue;
1463
1505
  }
1506
+ function normalizeExploreDefaultView(value) {
1507
+ return EXPLORE_DEFAULT_VIEW_OPTIONS.some((option) => option.id === value)
1508
+ ? value
1509
+ : DEFAULT_GENERAL_CONFIGURATION.defaultExploreView;
1510
+ }
1464
1511
  function normalizeWeekendDays(value) {
1465
1512
  if (!Array.isArray(value)) {
1466
1513
  return [];
@@ -1484,18 +1531,27 @@ function clampNumber(value, min, max) {
1484
1531
  }
1485
1532
  return Math.min(Math.max(value, min), max);
1486
1533
  }
1487
- function timeToMinutes(value) {
1488
- const [hours, minutes] = value.split(':').map((part) => Number(part));
1489
- if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
1490
- return 0;
1491
- }
1492
- return clampNumber(hours * 60 + minutes, 0, 1440);
1534
+ const TIMESHEET_FREQUENCIES = [
1535
+ 'Daily',
1536
+ 'Weekly',
1537
+ 'BiWeekly',
1538
+ 'Monthly',
1539
+ ];
1540
+ function normalizeFrequency(value) {
1541
+ return typeof value === 'string' &&
1542
+ TIMESHEET_FREQUENCIES.includes(value)
1543
+ ? value
1544
+ : 'Weekly';
1493
1545
  }
1494
- function minutesToTime(value) {
1495
- const normalizedValue = clampNumber(value, 0, 1440);
1496
- const hours = Math.floor(normalizedValue / 60);
1497
- const minutes = normalizedValue % 60;
1498
- return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
1546
+ function maxDailyHoursGteHoursPerDay(group) {
1547
+ const maxDailyHours = group.get('timeSheetPolicy.maxDailyHours')?.value;
1548
+ const hoursPerDay = group.get('globalWorkingHours.hoursPerDay')?.value;
1549
+ if (typeof maxDailyHours === 'number' &&
1550
+ typeof hoursPerDay === 'number' &&
1551
+ maxDailyHours < hoursPerDay) {
1552
+ return { maxDailyBelowDaily: true };
1553
+ }
1554
+ return null;
1499
1555
  }
1500
1556
  function parseCsv(value) {
1501
1557
  return value
@@ -1542,5 +1598,5 @@ function formatDateOnly(value) {
1542
1598
  * Generated bundle index. Do not edit.
1543
1599
  */
1544
1600
 
1545
- export { DEFAULT_DATE_FORMAT_OPTIONS, DEFAULT_TIME_FORMAT_OPTIONS, DOTNET_DAY_DEFINITIONS, FIXED_CURRENCIES, RATE_SOURCE_OPTIONS, SCHEDULE_ITEM_TYPE_OPTIONS, SystemSettings, SystemSettingsHolidayEditor, WEEKEND_DAY_DEFINITIONS };
1601
+ export { DEFAULT_DATE_FORMAT_OPTIONS, DEFAULT_GENERAL_CONFIGURATION, DEFAULT_TIME_FORMAT_OPTIONS, DOTNET_DAY_DEFINITIONS, EXPLORE_DEFAULT_VIEW_OPTIONS, FIXED_CURRENCIES, GENERAL_CONFIGURATION_SETTING_KEY, RATE_SOURCE_OPTIONS, SCHEDULE_ITEM_TYPE_OPTIONS, SystemSettings, SystemSettingsHolidayEditor, TIMESHEET_FREQUENCY_OPTIONS, WEEKEND_DAY_DEFINITIONS };
1546
1602
  //# sourceMappingURL=masterteam-system-settings.mjs.map