@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.
- package/README.md +34 -34
- package/assets/i18n/ar.json +24 -0
- package/assets/i18n/en.json +24 -0
- package/assets/system-settings.css +2 -2
- package/fesm2022/masterteam-system-settings.mjs +218 -162
- package/fesm2022/masterteam-system-settings.mjs.map +1 -1
- package/package.json +2 -2
- package/types/masterteam-system-settings.d.ts +95 -60
|
@@ -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
|
-
|
|
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
|
-
|
|
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(\"
|
|
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 }] }],
|
|
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
|
-
|
|
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(
|
|
406
|
-
|
|
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(
|
|
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
|
-
|
|
549
|
+
exploreDefaultViewOptions = computed(() => {
|
|
514
550
|
this.activeLang();
|
|
515
|
-
return
|
|
516
|
-
id:
|
|
517
|
-
|
|
518
|
-
|
|
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: "
|
|
521
|
-
|
|
556
|
+
}, ...(ngDevMode ? [{ debugName: "exploreDefaultViewOptions" }] : /* istanbul ignore next */ []));
|
|
557
|
+
frequencyOptions = computed(() => {
|
|
522
558
|
this.activeLang();
|
|
523
|
-
return
|
|
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: "
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
-
|
|
891
|
-
|
|
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
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
-
|
|
994
|
-
|
|
995
|
-
defaults.
|
|
996
|
-
|
|
997
|
-
|
|
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
|
-
|
|
1009
|
-
|
|
1010
|
-
defaults.
|
|
1011
|
-
|
|
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(
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
holidays: getStringArray(
|
|
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
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
-
|
|
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:
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
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 [
|
|
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 [
|
|
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
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
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
|
|
1495
|
-
const
|
|
1496
|
-
const
|
|
1497
|
-
|
|
1498
|
-
|
|
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
|