Neues Kalendermodul und DevExpress Übersetzungen

This commit is contained in:
2026-07-09 11:39:24 +02:00
parent 22c576af7b
commit 4d016f3ab0
29 changed files with 922 additions and 313 deletions

View File

@@ -193,6 +193,7 @@
<HintPath>..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Extensions.FileSystemGlobbing, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.WebHelpers.3.3.0\lib\net45\Microsoft.Web.Helpers.dll</HintPath>
</Reference>
@@ -400,6 +401,7 @@
<Compile Include="Util\JsonPerson.cs" />
<Compile Include="Util\SchedulerUtils\CustomAppointmentTemplateContainer.cs" />
<Compile Include="Util\SchedulerUtils\EmployeeAvailabilityObject.cs" />
<Compile Include="Util\SchedulerUtils\OwnSoftSchedulerLocalizer.cs" />
<Compile Include="Util\ServiceRecord2Validation.cs" />
<Compile Include="Util\SignatureUtils.cs" />
<Compile Include="Util\SupportConceptStatisticsData.cs" />

View File

@@ -12641,4 +12641,13 @@ a.text-bewo-report:hover, a.text-bewo-report:focus {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='25' height='25' viewBox='0 0 20 20'%3E%3Cg %3E%3Cpolygon fill='%23FFCA00' points='20 10 10 0 0 0 20 20'/%3E%3Cpolygon fill='%23FFCA00' points='0 10 0 20 10 20'/%3E%3C/g%3E%3C/svg%3E");
}
@media (max-width: 575.98px) {
.btn-sm-auto {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
border-radius: 0.2rem;
}
}
/*# sourceMappingURL=style.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -255,4 +255,13 @@ $font-family-sans-serif: 'Signika Negative', sans-serif;
.bewo-dev-bg {
background-color: #000000;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='25' height='25' viewBox='0 0 20 20'%3E%3Cg %3E%3Cpolygon fill='%23FFCA00' points='20 10 10 0 0 0 20 20'/%3E%3Cpolygon fill='%23FFCA00' points='0 10 0 20 10 20'/%3E%3C/g%3E%3C/svg%3E");
}
@media(max-width: 575.98px) {
.btn-sm-auto {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
border-radius: 0.2rem;
}
}

View File

@@ -121,6 +121,7 @@ namespace BeWoPlanerMobil.Controllers
Model.PossibleCustomers = CustomerService.GetAllAuthorizedCompactCustomers();
Model.PossibleResources = KalenderService.GetAllResources();
// Ressourcen
if(Model.HasRightToInsertRessourceAppointments || Model.HasRightToViewAllResourceAppointments)
{
var allResources = KalenderService.GetAllResources().OrderBy(r => r.Name).ToList();
@@ -135,6 +136,7 @@ namespace BeWoPlanerMobil.Controllers
Model.ResourceCategories2Resources = categories2Resources.OrderBy(category2Resources => category2Resources.Key.DisplayName).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
// Teams
Model.MyTeamEmployees = EmployeeService.GetAllTeamMember(compactEmployee).OrderBy(employee => employee.LastName).ToList();
if(Model.HasRightToViewTeams)
@@ -143,6 +145,7 @@ namespace BeWoPlanerMobil.Controllers
}
Model.TeamMemberCustomerOids = EmployeeService.LoadTeamsRelatedCustomerOids(employeeOid);
// /Teams
Model.SelectedEmployeesForFiltering = Model.PossibleEmployees.Where(possibleEmployee => Model.SelectedEmployeeOidsForFiltering?.Contains(possibleEmployee.EmployeeOid) ?? false).ToList();
Model.SelectedCustomersForFiltering = Model.PossibleCustomers.Where(possibleCustomer => Model.SelectedCustomerOidsForFiltering?.Contains(possibleCustomer.CustomerOid) ?? false).ToList();
@@ -171,7 +174,7 @@ namespace BeWoPlanerMobil.Controllers
var intervalStart = DateTimeExtensions.GetDayOfWeek(DayOfWeek.Monday);
var intervalEnd = intervalStart.AddDays(7);
var allAppointments = KalenderService.LoadFilteredAppointmentsMitAufgaben
var allAppointments = KalenderService.LoadFilteredAppointmentsMitAufgabenForMoK
(
Model.HasRightKalenderMitarbeitertermineAnsehen,
employeeOid,
@@ -278,24 +281,44 @@ namespace BeWoPlanerMobil.Controllers
if(Model.HasRightKalenderRessourcenTermineAndererAendern is false)
{
appointments
.Where(appointment => appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false && appointment.ResourceList.Any())
.Where(appointment =>
appointment.IsTask is false &&
appointment.IsAbsenceTime is false &&
appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false && appointment.ResourceList.Any())
.DoForEach(appointment => appointment.CanBeEdited = false);
}
if(Model.HasRightKalenderKlientenTermineAendern is false)
{
appointments
.Where(appointment => appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false && appointment.CustomerList.Any(customer => relatedCustomerOids.Contains(customer.CustomerOid) is false))
.Where(appointment =>
appointment.IsTask is false &&
appointment.IsAbsenceTime is false &&
appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false && appointment.CustomerList.Any())
.DoForEach(appointment => appointment.CanBeEdited = false);
}
if(Model.HasRightKalenderMitarbeiterTermineAendern is false)
{
appointments
.Where(appointment => appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false)
.Where(appointment =>
appointment.IsTask is false &&
appointment.IsAbsenceTime is false &&
appointment.Originator.Equals(Model.LoggedInCompactEmployee) is false)
.DoForEach(appointment => appointment.CanBeEdited = false);
}
foreach(var appointment in appointments.Where(apt => apt.IsTask is false && apt.IsAbsenceTime is false && apt.Originator.Equals(Model.LoggedInCompactEmployee) is false && apt.CustomerList.Any()))
{
var canEdit = appointment.CanBeEdited;
var canView = appointment.CanBeViewed;
var canDelete = appointment.CanBeDeleted;
var subject = appointment.Subject;
}
var x = appointments.Where(w => w.SchedulerAppointmentOid is null).ToList();
Model.Appointments = appointments;
LoadNotificationCount();
@@ -1580,7 +1603,7 @@ namespace BeWoPlanerMobil.Controllers
}
AppointmentModel.SelectedResourceOids = selectedOids.Length == 0 ? new List<long>() : selectedOids.Split(',').Select(long.Parse).ToList();
return JsonConvert.SerializeObject(AppointmentModel.SelectedResourceOids?.Count ?? 0);
}
}

View File

@@ -10,7 +10,6 @@ using BeWoPlanerMobil.Service;
using BeWoPlanerMobil.Util;
using BS.Shared;
using BS.Shared.DataContracts;
using DevExpress.XtraPrinting;
using HttpCookie = System.Web.HttpCookie;

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace BeWoPlanerMobil {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class DXLocalization {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal DXLocalization() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if(object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BeWoPlanerMobil.DXLocalization", typeof(DXLocalization).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ASPxSchedulerStringId.FloatingActionButton_NewAppointment" xml:space="preserve">
<value>Neuer Termin</value>
</data>
<data name="ASPxSchedulerStringId.ToolTip_DeleteAppointment" xml:space="preserve">
<value>Löschen</value>
</data>
<data name="ASPxSchedulerStringId.FloatingActionButton_DeleteAppointment" xml:space="preserve">
<value>Löschen</value>
</data>
<data name="SchedulerStringId.AppointmentLabel_Birthday" xml:space="preserve">
<value>Geburtstag</value>
</data>
<data name="SchedulerStringId.ViewShortDisplayName_Day" xml:space="preserve">
<value>Tag</value>
</data>
<data name="ASPxEditorsStringId.Calendar_Today" xml:space="preserve">
<value>Heute</value>
</data>
<data name="SchedulerStringId.ViewShortDisplayName_WorkDays" xml:space="preserve">
<value>Arbeitswoche</value>
</data>
</root>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -9,6 +9,7 @@ using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using BeWoPlanerMobil.Util.SchedulerUtils;
namespace BeWoPlanerMobil
@@ -33,6 +34,12 @@ namespace BeWoPlanerMobil
BundleConfig.RegisterBundles(BundleTable.Bundles);
XmlConfigurator.Configure();
OwnSoftSchedulerLocalizer.Activate();
// Für den Localizer. Für Release wieder entfernen und durch die Zeile darunter ersetzen
//DevExpress.Utils.Localization.XtraLocalizer.EnableTraceSource("BeWoPlanerMobil");
//RELEASE: DevExpress.Utils.Localization.XtraLocalizer.UserResourceManager = DXLocalization.ResourceManager;
}
protected void Application_BeginRequest(object sender, EventArgs e)
@@ -41,6 +48,9 @@ namespace BeWoPlanerMobil
// ToDo: Könnte Probleme beim Login machen, falls der den Header der Login-Anfrage benutzt.
Response.Headers["Referrer-Policy"] = "no-referrer";
Thread.CurrentThread.CurrentCulture = _CultureInfo;
Thread.CurrentThread.CurrentUICulture = _CultureInfo;
}
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)

View File

@@ -34,6 +34,8 @@ namespace BeWoPlanerMobil.Models
public bool HasServiceRecordEntry { get; set; }
public long? OriginatorOid { get; set; }
public int? RecurrenceIndex { get; set; }
public bool ShowEmployeeColors { get; set; }
public List<ServiceRecordDC> ServiceRecordList { get; set; }

View File

@@ -10,7 +10,20 @@ namespace BeWoPlanerMobil.Models
public List<long> SelectedResourceOids { get; set; }
public SchedulerViewType CurrentSchedulerViewType { get; set; }
public List<long> SelectedEmployeeOidsForFiltering { get; set; }
private List<long> _SelectedEmployeeOidsForFiltering;
public List<long> SelectedEmployeeOidsForFiltering
{
get
{
return _SelectedEmployeeOidsForFiltering;
}
set
{
_SelectedEmployeeOidsForFiltering = value;
}
}
public List<long> SelectedCustomerOidsForFiltering { get; set; }
public List<long> SelectedResourceOidsForFiltering { get; set; }

View File

@@ -0,0 +1,44 @@
using System.Diagnostics;
using DevExpress.Utils.Localization.Internal;
using DevExpress.XtraScheduler.Localization;
namespace BeWoPlanerMobil.Util.SchedulerUtils
{
public class OwnSoftSchedulerLocalizer : SchedulerLocalizer
{
public override string GetLocalizedString(SchedulerStringId id)
{
switch(id)
{
case SchedulerStringId.ViewShortDisplayName_Day:
return "Tag";
case SchedulerStringId.ViewShortDisplayName_Week:
return "Woche";
case SchedulerStringId.TimeScaleDisplayName_Week:
return "Woche";
case SchedulerStringId.ViewShortDisplayName_WorkDays:
return "Arbeitswoche";
case SchedulerStringId.ViewDisplayName_WorkDays:
return "Arbeitswoche";
case SchedulerStringId.ViewShortDisplayName_Timeline:
return "Zeitleiste";
case SchedulerStringId.ViewDisplayName_Timeline:
return "Zeitleiste";
case SchedulerStringId.ViewDisplayName_Month:
return "Monat";
case SchedulerStringId.ViewShortDisplayName_Month:
return "Monat";
}
return base.GetLocalizedString(id);
}
public static void Activate()
{
var localizer = new OwnSoftSchedulerLocalizer();
var provider = new DefaultActiveLocalizerProvider<SchedulerStringId>(localizer);
SetActiveLocalizerProvider(provider);
}
}
}

View File

@@ -116,7 +116,7 @@
</div>
<input class="form-control w-100" type="text" placeholder="Suchen..." oninput="employeeListSearchOnChange()" id="employee-search-input" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="resetEmployeeSearch()">
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="resetEmployeeSearch()">
<span class="fas fa-times-circle"></span>
</button>
</div>
@@ -137,7 +137,7 @@
<div class="card-body">
@foreach(var team in Model.MyTeams)
{
<button type="button" class="btn btn-bewo-teams w-100 my-2" onclick="selectTeamForAppointment(@team.TeamOid)">@team.Name</button>
<button type="button" class="btn btn-sm btn-bewo-teams w-100 my-2" onclick="selectTeamForAppointment(@team.TeamOid)">@team.Name</button>
}
</div>
</div>

View File

@@ -1,5 +1,4 @@
@using BeWoPlanerMobil.Util
<script type="text/javascript">
<script type="text/javascript">
function onAppointmentDragTipDisplaying(s, e) {
const newIntervalText = e.toolTip.ConvertIntervalToString(e.data.GetInterval());

View File

@@ -7,7 +7,8 @@
Html.EnableClientValidation();
Html.EnableUnobtrusiveJavaScript();
var isNew = Model.Oid is null;
// Ist bei Serientermininstanzen ebenfalls null!
var isNew = Model.Oid is null && Model.RecurrenceIndex == 0 && Model.RecurrenceInfo is null;
var cancelButtonText = "Abbrechen";
@@ -84,6 +85,11 @@
var showResourceButton = (Model.HasRightKalenderRessourcentermineAnsehen && Model.Oid.HasValue) ||
(Model.Oid.HasValue && (Model.HasRightKalenderRessourcenTermineAendern && isOriginator || isOriginator is false && Model.HasRightKalenderRessourcenTermineAndererAendern)) ||
(Model.Oid is null && Model.HasRightKalenderRessourcenTermineAnlegen);
if(areButtonsVisible != Model.CanBeEdited)
{
}
}
<style type="text/css">
@@ -95,168 +101,154 @@
@using(Html.BeginForm())
{
<table id="abc-table" class="w-100">
@* Betreff *@
<tr>
<td colspan="2">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Betreff</span>
</div>
<input class="form-control" type="text" @disabled id="Subject" name="Subject" value="@Model.Subject" />
</div>
</td>
</tr>
@* Ort *@
<tr>
<td colspan="2">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Ort</span>
</div>
<input class="form-control" type="text" @disabled id="Location" name="Location" value="@Model.Location" />
</div>
</td>
</tr>
@* Start *@
<tr>
<td>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Start</span>
</div>
<input class="form-control" type="@dateInputType" @disabled id="StartDate" name="StartDate" value="@start" />
</div>
</td>
<td>
<div class="input-group pl-2 mb-2">
<div class="input-group-prepend">
<div class="input-group-text">
@Html.DevExpress().CheckBox(
settings =>
{
settings.Name = nameof(SchedulerAppointmentDC.AllDay);
settings.Width = Unit.Percentage(100);
settings.ReadOnly = disabled.Length > 0;
}).Bind(Model.AllDay).GetHtml()
</div>
</div>
<div class="input-group-append">
<span class="input-group-text">Ganztägig</span>
</div>
</div>
</td>
</tr>
@* Ende *@
<tr>
<td colspan="2">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Ende</span>
</div>
<input class="form-control" type="@dateInputType" @disabled id="EndDate" name="EndDate" value="@end" />
</div>
</td>
</tr>
@* Privat *@
<tr>
<td >
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">
@Html.DevExpress().CheckBox(
settings =>
{
settings.Name = nameof(SchedulerAppointmentDC.IsPrivate);
settings.Width = Unit.Percentage(100);
settings.Properties.RootStyle.CssClass = "";
settings.ReadOnly = disabled.Length > 0;
}).Bind(Model.IsPrivate).GetHtml()
<div class="row" id="abc-table">
<div class="col">
<div class="form-row">
<div class="col-md">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Betreff</span>
</div>
<input class="form-control" type="text" @disabled id="Subject" name="Subject" value="@Model.Subject" />
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Ort</span>
</div>
</div>
<div class="input-group-append">
<span class="input-group-text">Privat</span>
<input class="form-control" type="text" @disabled id="Location" name="Location" value="@Model.Location" />
</div>
</div>
</td>
</tr>
</div>
<div class="form-row">
<div class="col-md">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Start</span>
</div>
<input class="form-control" type="@dateInputType" @disabled id="StartDate" name="StartDate" value="@start" />
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">Ende</span>
</div>
<input class="form-control" type="@dateInputType" @disabled id="EndDate" name="EndDate" value="@end" />
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text">
@Html.DevExpress().CheckBox(
settings =>
{
settings.Name = nameof(SchedulerAppointmentDC.IsPrivate);
settings.Width = Unit.Percentage(100);
settings.Properties.RootStyle.CssClass = "";
settings.ReadOnly = disabled.Length > 0;
}).Bind(Model.IsPrivate).GetHtml()
</div>
</div>
<div class="input-group-append">
<span class="input-group-text">Privat</span>
</div>
</div>
</div>
<div class="col-md">
<div class="input-group pl-2 mb-2 justify-content-end">
<div class="input-group-prepend">
<div class="input-group-text">
@Html.DevExpress().CheckBox(
settings =>
{
settings.Name = nameof(SchedulerAppointmentDC.AllDay);
settings.Width = Unit.Percentage(100);
settings.ReadOnly = disabled.Length > 0;
}).Bind(Model.AllDay).GetHtml()
</div>
</div>
<div class="input-group-append">
<span class="input-group-text">Ganztägig</span>
</div>
</div>
</div>
</div>
@if(Model.HasRightKalenderMitarbeitertermineAnsehen || Model.HasRightKalenderKliententermineAnsehen || Model.HasRightKalenderRessourcentermineAnsehen)
{
<tr>
@* colspan="4" *@
<td colspan="2">
<table class="w-100">
<tr>
<td style="width: 33%; padding: .25em;">
@if(showEmployeeButton)
{
@Html.Partial("CustomEmployeeSelectPartial", Model)
}
</td>
<td style="width: 33%; padding: .25em;">
@if(showCustomerButton)
{
@Html.Partial("CustomCustomerSelectPartial", Model)
}
</td>
<td style="width: 33%; padding: .25em;">
@if(showResourceButton)
{
@Html.Partial("CustomResourceSelectPartial", Model)
}
</td>
</tr>
</table>
</td>
</tr>
}
@if(Model.HasRightKalenderMitarbeitertermineAnsehen || Model.HasRightKalenderKliententermineAnsehen || Model.HasRightKalenderRessourcentermineAnsehen)
{
<div class="form-row justify-content-center">
@if(showEmployeeButton)
{
@Html.Partial("CustomEmployeeSelectPartial", Model)
}
@* Notiz *@
<tr>
<td colspan="2">
<div class="form-group">
<label for="Description">Notiz</label>
<textarea class="form-control" @disabled id="Description" name="Description">@Model.Description</textarea>
</div>
</td>
</tr>
</table>
@if(showCustomerButton)
{
@Html.Partial("CustomCustomerSelectPartial", Model)
}
@Html.DevExpress().AppointmentRecurrenceForm(ViewBag.AppointmentRecurrenceFormSettings).GetHtml()
@if(showResourceButton)
{
@Html.Partial("CustomResourceSelectPartial", Model)
}
</div>
}
<table style="width: 100%">
<tr>
@if(areButtonsVisible)
{
<button type="button" class="btn btn-primary mr-2" id="Apply" name="Apply" onclick="OnAppointmentFormSave()">OK</button>
}
<div class="form-row">
<div class="col-md">
<div class="form-group">
<label for="Description">Notiz</label>
<textarea class="form-control" @disabled id="Description" name="Description">@Model.Description</textarea>
</div>
</div>
</div>
<div id="recurrence-container">
@{
var recurrenceSettings = (AppointmentRecurrenceFormSettings) ViewBag.AppointmentRecurrenceFormSettings;
<button type="button" class="btn btn-primary mr-2" id="Cancel" name="Cancel" onclick="OnAppointmentFormCancel()">@cancelButtonText</button>
recurrenceSettings.Enabled = areButtonsVisible;
}
@if(isDeleteButtonVisible)
{
<button type="button" class="btn btn-danger" id="Delete" name="Delete" onclick="OnAppointmentFormDelete()">Löschen</button>
}
</tr>
</table>
@Html.DevExpress().AppointmentRecurrenceForm(recurrenceSettings).GetHtml()
</div>
<div class="form-row">
<div class="col">
<div class="float-right">
@if(areButtonsVisible)
{
<button type="button" class="btn btn-sm-auto btn-primary mr-2" id="Apply" name="Apply" onclick="OnAppointmentFormSave()">OK</button>
}
<table class="w-100">
<tr>
<td style="width: 100%;">
<button type="button" class="btn btn-sm-auto btn-primary mr-2" id="Cancel" name="Cancel" onclick="OnAppointmentFormCancel()">@cancelButtonText</button>
@if(isDeleteButtonVisible)
{
<button type="button" class="btn btn-sm-auto btn-danger" id="Delete" name="Delete" onclick="OnAppointmentFormDelete()">Löschen</button>
}
</div>
</div>
</div>
<div>
@Html.DevExpress().SchedulerStatusInfo(
settings =>
{
settings.Name = "schedulerStatusInfo";
settings.Priority = 1;
settings.SchedulerName = "scheduler";
}).GetHtml()
</td>
</tr>
</table>
settings =>
{
settings.Name = "schedulerStatusInfo";
settings.Priority = 1;
settings.SchedulerName = "scheduler";
}).GetHtml()
</div>
</div>
</div>
}

View File

@@ -12,9 +12,7 @@
const participationInfos = currentApt.ParticipationInfos;
const resourceInfos = currentApt.ResourceInfos;
const customerInfos = currentApt.CustomerInfos;
logInfo(`Mitarbeiter: ${participationInfos.length}\r\nKlienten: ${customerInfos.length}\r\nRessourcen: ${resourceInfos.length}`);
console.log(currentApt); // ToDo: Icon bei Serientermin! Index auch?
let bgClass = "";
$("#tool-tip-info").empty();
@@ -57,7 +55,6 @@
$("#resources-container").append(`<span class="small pr-1">Ressourcen:</span>`);
resourceInfos.forEach((info) => {
logInfo2(`Farbe der Ressource <<${info.ResourceName}>>: ${info.ResourceColor}`);
$("#resources-container").append(`<span class="badge badge-light border"><div class="mr-1" style="display:inline-block;border-radius:3px;vertical-align:middle;width:10px;height:10px;border:1px slategray;background-color: ${info.ResourceColor};"></div>${info.ResourceName}</span>`);
});
}
@@ -66,7 +63,7 @@
const textInterval = e.toolTip.ConvertIntervalToString(currentApt.interval);
$('#tool-tip-title').html(textInterval);
$('#tool-tip-title').html(`${textInterval}: ${currentApt.GetSubject()}`);
if(currentApt.CanBeDeleted === false) {
$("#aptToolTipDelete").hide();
@@ -117,4 +114,12 @@
<div id="originator-container"></div>
</div>
</div>
<div class="card-footer m-0 p-1">
<button type="button" id="aptToolTipEdit" class="btn btn-sm btn-primary" onclick="onAptToolTipEditClick()">
Bearbeiten
</button>
<button type="button" id="aptToolTipDelete" class="btn btn-sm btn-danger float-right" onclick="onAptToolTipDeleteClick()">
Löschen
</button>
</div>
</div>

View File

@@ -7,15 +7,15 @@
var allChecked = areAllSelected ? "checked" : string.Empty;
var canEdit = Model.Oid.HasValue && Model.HasRightKalenderKlientenTermineAendern;
var canCreate = Model.Oid is null && Model.HasRightKalenderKlientenTermineAnlegen;
var canCreate = Model.Oid is null && Model.RecurrenceIndex == 0 && Model.RecurrenceInfo is null && Model.HasRightKalenderKlientenTermineAnlegen;
var checkBoxEnabled = canEdit || canCreate;
var disabled = checkBoxEnabled ? string.Empty : "disabled";
}
<div class="dropdown w-100" id="customers-dropdown">
<button class="btn btn-bewo-customers dropdown-toggle w-100" type="button" data-toggle="dropdown">
<div class="dropdown pr-1" id="customers-dropdown">
<button class="btn btn-sm-auto btn-bewo-customers dropdown-toggle w-100" type="button" data-toggle="dropdown">
Klienten <span class="badge badge-light" id="apt-cus-badge">@Model.SelectedCustomerOids.Count</span>
</button>
<div class="dropdown-menu" onclick="event.stopPropagation();">
@@ -28,7 +28,7 @@
</div>
<input type="text" class="form-control" @disabled id="cus-drop-search-input" placeholder="Suchen ..." oninput="onNewSearchInput('cus')">
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary" @disabled onclick="resetNewSearch('cus')">
<button type="button" class="btn btn-sm-auto btn-outline-secondary" @disabled onclick="resetNewSearch('cus')">
<span class="fas fa-times-circle"></span>
</button>
</div>

View File

@@ -37,15 +37,15 @@
var allChecked = areAllSelected ? "checked" : string.Empty;
var isNew = Model.Oid is null;
var isNew = Model.Oid is null && Model.RecurrenceIndex == 0 && Model.RecurrenceInfo is null;
var isEdit = isNew is false;
var checkBoxEnabled = isEdit && Model.HasRightKalenderMitarbeiterTermineAendern || isNew && Model.HasRightKalenderMitarbeiterTermineAnlegen;
var disabled = checkBoxEnabled is false || (Model.CanBeEdited is false && isNew is false) ? "disabled" : string.Empty;
}
<div class="dropdown w-100" id="employees-dropdown">
<button class="btn btn-bewo-employee dropdown-toggle w-100" type="button" data-toggle="dropdown">
<div class="dropdown pr-1" id="employees-dropdown">
<button class="btn btn-sm-auto btn-bewo-employee dropdown-toggle w-100" type="button" data-toggle="dropdown">
Mitarbeiter <span class="badge badge-light" id="apt-emp-badge">@Model.SelectedEmployee2SchedulerAppointments.Count</span>
</button>
<div class="dropdown-menu" onclick="event.stopPropagation();">
@@ -58,7 +58,7 @@
</div>
<input type="text" class="form-control" @disabled id="emp-drop-search-input" placeholder="Suchen ..." oninput="onNewSearchInput('emp')">
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary" @disabled onclick="resetNewSearch('emp')">
<button type="button" class="btn btn-sm-auto btn-outline-secondary" @disabled onclick="resetNewSearch('emp')">
<span class="fas fa-times-circle"></span>
</button>
</div>

View File

@@ -21,7 +21,7 @@
var checkedValue = areAllSelected ? "checked" : string.Empty;
var isOriginator = Model.OriginatorOid.HasValue && Model.OriginatorOid.Value == Model.LoggedInCompactEmployee.EmployeeOid;
var isNew = Model.Oid is null;
var isNew = Model.Oid is null && Model.RecurrenceIndex == 0 && Model.RecurrenceInfo is null;
var canEditResApt = Model.HasRightKalenderRessourcenTermineAendern;
var canEditOthersResApt = Model.HasRightKalenderRessourcenTermineAndererAendern;
var canCreateResApt = Model.HasRightKalenderRessourcenTermineAnlegen;
@@ -33,8 +33,8 @@
var disabled = isDisabled ? "disabled" : string.Empty;
}
<div class="dropdown w-100" id="resources-dropdown">
<button class="btn btn-bewo-resource dropdown-toggle w-100" type="button" data-toggle="dropdown">
<div class="dropdown pr-1" id="resources-dropdown">
<button class="btn btn-sm-auto btn-bewo-resource dropdown-toggle w-100" type="button" data-toggle="dropdown">
Ressourcen <span class="badge badge-light" id="apt-res-badge">@Model.SelectedResourceOids.Count</span>
</button>
<div class="dropdown-menu" onclick="event.stopPropagation();">
@@ -47,7 +47,7 @@
</div>
<input type="text" class="form-control" id="res-drop-search-input" placeholder="Suchen ..." oninput="onNewResourceSeachInput()">
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary" onclick="resetNewResourceSearch()">
<button type="button" class="btn btn-sm-auto btn-outline-secondary" onclick="resetNewResourceSearch()">
<span class="fas fa-times-circle"></span>
</button>
</div>
@@ -110,31 +110,4 @@
</nav>
</div>
</div>
</div>
@* ToDo: Mit den Kategorien wie im alten Kalendermodul bauen!
@for(var i = 0; i < Model.PossibleResources.Count; i++)
{
var resource = Model.PossibleResources[i];
var isChecked = resource.ResourceOid.HasValue && Model.SelectedResourceOids.Contains(resource.ResourceOid.Value) ? "checked" : string.Empty;
var dNone = i / Model.ResourcePageLimit + 1 != 1 ? " d-none" : string.Empty;
<div class="dropdown-item w-100 @dNone" id="dropdown-item-@i">
<form class="form-inline justify-content-between">
<div class="form-group form-check">
<input class="form-check-input" type="checkbox" id="apt-edit-res-@resource.ResourceOid.Value" @isChecked onclick="updateEmployeeCustomerResourceSelection('res')"/>
<label for="apt-edit-res-@resource.ResourceOid.Value" class="form-check-label">
@resource.DetailDescription
</label>
</div>
@if(WebUtils.CheckColorString(resource.Color))
{
<div class="float-right" style="width: 10px; height: 10px; background-color: @resource.Color; border: 1px solid @resource.Color; border-radius: 3px;"></div>
}
</form>
</div>
}*@
</div>

View File

@@ -6,6 +6,15 @@
}
<script type="text/javascript">
$(document).ready(() => {
const newAptBtn = $("#scheduler_fab").children().find(".dx-fab-context-text");
if(newAptBtn.length) {
newAptBtn.empty();
newAptBtn.append("<span>Neuer Termin</span>");
}
});
function UpdateSchedulerHeight() {
scheduler.SetHeight(1);
@@ -18,22 +27,44 @@
scheduler.SetHeight(containerHeight);
}
function getLabelByTextFromRecurrenceForm(labelText) {
return $("#appointmentRecurrenceForm_AptRecCtl_mainDiv").filter(function() {
return $(this).text().trim() === labelText;
});
}
function resizeSchedulerEditForm() {
const editFormPopup = $("#abc-table").parent().parent().parent();
const vw = $(window).width();
if(editFormPopup.css("top") !== undefined) {
editFormPopup.css("top", "50px");
const recurrence = $("#appointmentRecurrenceForm_AptRecCtl_mainDiv label:contains('Recurrence')");
const daily = $("#appointmentRecurrenceForm_AptRecCtl_mainDiv label:contains('Daily')");
const weekly = $("#appointmentRecurrenceForm_AptRecCtl_mainDiv label:contains('Weekly')");
const monthly = $("#appointmentRecurrenceForm_AptRecCtl_mainDiv label:contains('Monthly')");
const yearly = $("#appointmentRecurrenceForm_AptRecCtl_mainDiv label:contains('Yearly')");
recurrence.text("Serie");
daily.text("Täglich");
weekly.text("Wöchentlich");
monthly.text("Monatlich");
yearly.text("Jährlich");
}
if(editFormPopup.outerWidth() !== undefined) {
$.get("@Url.Action("GetEmployeePageCount")", function(editFormInfo) {
pageCountCallback(editFormInfo, "emp");
pageCountCallback(editFormInfo, "emp");
});
$.get("@Url.Action("GetCustomerPageCount")", function(editFormInfo) {
pageCountCallback(editFormInfo, "cus");
pageCountCallback(editFormInfo, "cus");
});
$.get("@Url.Action("GetResourcePageCount")", function(editFormInfo) {
pageCountCallback(editFormInfo, "res");
pageCountCallback(editFormInfo, "res");
});
}
@@ -66,11 +97,11 @@
}
}
function pageCountCallback(editFormInfo, prefix) {
function pageCountCallback(editFormInfo, prefix) {
const info = JSON.parse(editFormInfo);
const items = $(`#dropdown-${prefix}-itm-container .dropdown-item`);
const items = $(`#dropdown-${prefix}-itm-container .dropdown-item`);
switch(prefix) {
switch(prefix) {
case "emp":
aptEmpSelPageCount = info.PageCount;
aptEmpSelPageLimit = info.PageLimit;
@@ -88,7 +119,7 @@
break;
}
window.buildPagination(1, 5, 1, prefix);
window.buildPagination(1, 5, 1, prefix);
}
function OnAppointmentFormSave(s, e) {
@@ -97,13 +128,13 @@
}
}
function OnAppointmentFormCancel(s, e) {
scheduler.AppointmentFormCancel();
}
function OnAppointmentFormCancel(s, e) {
scheduler.AppointmentFormCancel();
}
function OnAppointmentFormDelete(s, e) {
scheduler.AppointmentFormDelete();
}
function OnAppointmentFormDelete(s, e) {
scheduler.AppointmentFormDelete();
}
function IsValidAppointment() {
$.validator.unobtrusive.parse("form");
@@ -249,25 +280,25 @@
}
function performReload(shouldDoReloadNotifications) {
if(shouldDoReloadNotifications === false) {
return;
}
if(shouldDoReloadNotifications === false) {
return;
}
$("#scheduler-notification-container").load("@Url.Action("GetNotifications")");
}
function reloadScheduler(shouldDoReloadNotifications) {
scheduler.PerformCallback({apptID: "", actionId: "Reload", args: null}, () => {performReload(shouldDoReloadNotifications); hideSpinner(); });
scheduler.PerformCallback({apptID: "", actionId: "Reload", args: null}, () => {performReload(shouldDoReloadNotifications); hideSpinner(); });
}
@* CustomECRSelectionPartial *@
function onNewSearchInput(prefix) {
var searchText = $(`#${prefix}-drop-search-input`).val();
var searchText = $(`#${prefix}-drop-search-input`).val();
const menuItems = $(`#dropdown-${prefix}-itm-container .dropdown-item`);
const menuItems = $(`#dropdown-${prefix}-itm-container .dropdown-item`);
if(searchText === null || searchText === undefined || searchText.length === 0) {
menuItems.show();
menuItems.show();
return;
}
@@ -285,7 +316,7 @@
}
function resetNewSearch(prefix) {
$(`#${prefix}-drop-search-input`).val("");
$(`#${prefix}-drop-search-input`).val("");
buildPagination(1, 5, 1, prefix);
showPage(1, prefix);
@@ -314,7 +345,7 @@
var aptResSelPageLimit = 0;
function buildPagination(firstShownButton, lastShownButton, activeButton, prefix) {
const pagination = $(`#apt-${prefix}-pagination`);
const pagination = $(`#apt-${prefix}-pagination`);
pagination.empty();
var pageCount = 1;
@@ -335,38 +366,34 @@
break;
}
if(prefix === "res") {
logInfo2(`Es gibt ${pageCount} Seiten für die Ressourcen`);
}
if(pageCount <= 1) {
$(`#apt-${prefix}-pag-divider, #apt-${prefix}-pag-dropdow-item`).hide();
$(`#apt-${prefix}-pag-divider, #apt-${prefix}-pag-dropdow-item`).hide();
return;
}
$(`#apt-${prefix}-pag-divider, #apt-${prefix}-pag-dropdow-item`).show();
$(`#apt-${prefix}-pag-divider, #apt-${prefix}-pag-dropdow-item`).show();
var limit = lastShownButton;
if(pageCount < limit) {
limit = pageCount;
if(pageCount < limit) {
limit = pageCount;
}
const firstPageLiClass = firstShownButton === 1 ? "page-item disabled" : "page-igem";
const lastPageLiClass = lastShownButton === pageCount ? "page-item disabled" : "page-igem";
const lastPageLiClass = lastShownButton === pageCount ? "page-item disabled" : "page-igem";
const prevPageLiClass = activeButton === 1 ? "page-item disabled" : "page-item";
const nextPageLiClass = activeButton === pageCount ? "page-item disabled" : "page-igem";
const nextPageLiClass = activeButton === pageCount ? "page-item disabled" : "page-igem";
$(`<li class="${firstPageLiClass}" id="first-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${1}, '${prefix}')"><span class="fas fa-angle-double-left"></span></button></li>`).appendTo(pagination);
$(`<li class="${prevPageLiClass}" id="prev-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${currentPage - 1}, '${prefix}')"><span class="fas fa-angle-left"></span></button></li>`).appendTo(pagination);
$(`<li class="${prevPageLiClass}" id="prev-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${currentPage - 1}, '${prefix}')"><span class="fas fa-angle-left"></span></button></li>`).appendTo(pagination);
for(let i = firstShownButton; i <= limit; i++) {
$(`<li class="page-item ${(i === activeButton ? "active" : "")}"><button class="page-link" tabindex="-1" type="button" onclick="showPage(${i}, '${prefix}')">${i}</button></li>`).appendTo(pagination);
$(`<li class="page-item ${(i === activeButton ? "active" : "")}"><button class="page-link" tabindex="-1" type="button" onclick="showPage(${i}, '${prefix}')">${i}</button></li>`).appendTo(pagination);
}
$(`<li class="${nextPageLiClass}" id="next-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${currentPage + 1}, '${prefix}')"><span class="fas fa-angle-right"></span></button></li>`).appendTo(pagination);
$(`<li class="${lastPageLiClass}" id="last-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${pageCount}, '${prefix}')"><span class="fas fa-angle-double-right"></span></button></li>`).appendTo(pagination);
$(`<li class="${nextPageLiClass}" id="next-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${currentPage + 1}, '${prefix}')"><span class="fas fa-angle-right"></span></button></li>`).appendTo(pagination);
$(`<li class="${lastPageLiClass}" id="last-page-li"><button type="button" class="page-link" tabeindex="-1" onclick="showPage(${pageCount}, '${prefix}')"><span class="fas fa-angle-double-right"></span></button></li>`).appendTo(pagination);
}
function showPage(page, prefix) {
@@ -388,8 +415,8 @@
break;
}
const total = (items.length / 10) | 0;
const currentPage = Math.max(1, Math.min(page, total));
const total = (items.length / 10) | 0;
const currentPage = Math.max(1, Math.min(page, total));
switch(prefix) {
case "emp":
@@ -403,28 +430,28 @@
break;
}
const start = (currentPage - 1) * 10;
const end = currentPage * 10;
const start = (currentPage - 1) * 10;
const end = currentPage * 10;
items.hide();
items.hide();
$.each(items.slice(start, end), function(index, item) {
$.each(items.slice(start, end), function(index, item) {
$(item).removeClass("d-none");
$(item).show();
});
const last = Math.min(pageCount, currentPage + 2);
const last = Math.min(pageCount, currentPage + 2);
const first = Math.max(1, last - 4);
buildPagination(first, last, currentPage, prefix);
buildPagination(first, last, currentPage, prefix);
}
function updateEmployeeCustomerResourceSelection(prefix) {
const checkedBoxes = $(`#dropdown-${prefix}-itm-container input[type=checkbox]:checked`);
const checkedBoxes = $(`#dropdown-${prefix}-itm-container input[type=checkbox]:checked`);
var url = "";
var url = "";
switch(prefix) {
switch(prefix) {
case "emp":
url = "@Url.Action("UpdateAppointmentEmployeeSelection")";
break;
@@ -434,7 +461,7 @@
case "res":
url = "@Url.Action("UpdateAppointmentResourceSelection")";
break;
}
}
var selectedOids = [];
@@ -449,7 +476,7 @@
showSpinner();
$.get(
url,
{ selectedOids: selectedOids.join(", ") },
{ selectedOids: selectedOids.join(", ") },
function(elementCount) {
$(`#apt-${prefix}-badge`).text(elementCount);
@@ -459,28 +486,28 @@
function selectAllEmployeeCustomerResource(prefix) {
const isChecked = $(`#apt-${prefix}-select-all`).prop("checked");
const isChecked = $(`#apt-${prefix}-select-all`).prop("checked");
$(`#dropdown-${prefix}-itm-container input[type=checkbox]`).prop("checked", isChecked);
$(`#dropdown-${prefix}-itm-container input[type=checkbox]`).prop("checked", isChecked);
updateEmployeeCustomerResourceSelection(prefix);
}
function categoryCardHeaderClick(collapsibleId) {
const collapsible = $(`#${collapsibleId}`);
function categoryCardHeaderClick(collapsibleId) {
const collapsible = $(`#${collapsibleId}`);
if(collapsible.length === false) {
return;
if(collapsible.length === false) {
return;
}
collapsible.collapse("toggle");
collapsible.collapse("toggle");
const e = window.event;
e.cancelBubble = true;
const e = window.event;
e.cancelBubble = true;
if(e.stopPropagation) {
e.stopPropagation();
}
if(e.stopPropagation) {
e.stopPropagation();
}
}
function onNewResourceSeachInput() {
@@ -490,7 +517,7 @@
const collapse = $(`#dropdown-res-itm-container .dropdown-item .collapse`);
if(searchText === null || searchText === undefined || searchText.length === 0) {
showAllResources();
showAllResources();
return;
}
@@ -498,7 +525,7 @@
$.each(category2Resources,
function(index, item) {
const categoryName = $(item).find("h6").text().toLowerCase();
const categoryName = $(item).find("h6").text().toLowerCase();
if(categoryName.includes(searchText)) {
$(item).show();
@@ -521,20 +548,20 @@
);
}
function resetNewResourceSearch() {
$(`#res-drop-search-input`).val("");
function resetNewResourceSearch() {
$(`#res-drop-search-input`).val("");
showAllResources();
showAllResources();
buildPagination(1, 5, 1, "res");
showPage(1, "res");
buildPagination(1, 5, 1, "res");
showPage(1, "res");
const e = window.event;
e.cancelBubble = true;
const e = window.event;
e.cancelBubble = true;
if(e.stopPropagation) {
e.stopPropagation();
}
if(e.stopPropagation) {
e.stopPropagation();
}
}
function showAllResources() {
@@ -551,7 +578,7 @@
});
});
collapse.collapse("show");
collapse.collapse("show");
}
@* /CustomECRSelectionPartial *@
@@ -562,9 +589,9 @@
@* ToolTip *@
var toolTipContext;
function onToolTipDisplaying(s, e) {
toolTipContext = e;
var toolTipContext;
function onToolTipDisplaying(s, e) {
toolTipContext = e;
switch(e.toolTip.type) {
case MVCxSchedulerToolTipType.Appointment:
@@ -573,7 +600,7 @@
onAppointmentDragTipDisplaying(s, e);
break;
}
}
}
</script>
<div class="dropdown">

View File

@@ -193,15 +193,9 @@
settings.CustomActionRouteValues = new { Controller = "DevExpressScheduler", Action = "CustomCallBackAction" };
settings.ClientSideEvents.ToolTipDisplaying = "onToolTipDisplaying";
settings.OptionsToolTips.SetAppointmentToolTipTemplateContent(() =>
{
Html.RenderPartial("CustomAppointmentToolTipPartial");
});
settings.OptionsToolTips.SetAppointmentToolTipTemplateContent(() => { Html.RenderPartial("CustomAppointmentToolTipPartial"); });
settings.OptionsToolTips.SetAppointmentMobileToolTipTemplateContent(() => { Html.RenderPartial("CustomAppointmentToolTipPartial"); });
settings.OptionsToolTips.SetAppointmentDragToolTipTemplateContent(() =>
{
Html.RenderPartial("CustomAppointmentDragToolTip");
});
settings.OptionsToolTips.SetAppointmentDragToolTipTemplateContent(() => { Html.RenderPartial("CustomAppointmentDragToolTip"); });
settings.OptionsCustomization.AllowInplaceEditor = UsedAppointmentType.None;
settings.OptionsCustomization.AllowDisplayAppointmentFlyout = false;
@@ -384,7 +378,9 @@
IsTask = container.Appointment.CustomFields["IsTask"] is true,
DueDate = container.Appointment.CustomFields["DueDate"] is DateTime dueDate ? dueDate : null,
CompletedDate = container.Appointment.CustomFields["CompletedDate"] is DateTime completedDate ? completedDate : null,
OriginatorOid = (container.Appointment.CustomFields["Originator"] as CompactEmployeeDC)?.EmployeeOid
OriginatorOid = (container.Appointment.CustomFields["Originator"] as CompactEmployeeDC)?.EmployeeOid,
RecurrenceInfo = container.Appointment.RecurrenceInfo?.ToXml(),
RecurrenceIndex = container.Appointment.RecurrenceIndex
};
var appointmentModel = ViewData["EditableAppointmentModel"] != null ? (AppointmentModel)ViewData["EditableAppointmentModel"] : newModel;

View File

@@ -275,7 +275,7 @@
var $target;
var targetIndex;
// Prüfen ob die Tab-Ansicht sichtbar ist (mehrere Dokutypes vorhanden)
// Prüfen, ob die Tab-Ansicht sichtbar ist (mehrere Dokutypes vorhanden)
var $activeTabTextarea = $('#dokufelderTab .tab-pane.active textarea');
if ($activeTabTextarea.length > 0) {
// Das aktive Tab-Textarea verwenden; Index aus der ID auslesen (sb-doku-textarea-{i})

View File

@@ -32,7 +32,7 @@
oidString: selectedEmployeeOids.toString()
},
() => {
$("#one-day-scheduler-partial-container").load('@Url.Action("FetchAppointments", "Scheduler")');
@*$("#one-day-scheduler-partial-container").load('@Url.Action("FetchAppointments", "Scheduler")');*@
}
);
}

View File

@@ -81,6 +81,10 @@
<link type="text/css" rel="stylesheet" href="@Url.Content("~/Content/dx.common.css")" />
<link type="text/css" rel="stylesheet" href="@Url.Content("~/Content/dx.light.css")" />
<script>
DevExpress.localization.locale("de");
</script>
@* CSS für den neuen Kalender-Tooltip *@
<style type="text/css">
.toolTipPanel {
@@ -406,16 +410,6 @@
<ul class="navbar-nav ml-auto">
@if (Html.IsInDebugMode())
{
using (Html.BeginForm("RedirectToDevExpressScheduler", "Main", FormMethod.Post))
{
<li class="nav-item">
<button class="btn btn-link text-light no-underline" onclick="showSpinner()">
<i class="far fa-calendar-alt text-bewo-calendar"></i>
DX Kalender
</button>
</li>
}
<li class="nav-item">
<button class="btn btn-link text-light no-underline" type="button" onclick="printLocalStorage()">
<i class="fab fa-firefox-browser text-bewo-dev"></i>
@@ -433,6 +427,19 @@
</li>
}
}
@if(Model.IsAllowedToSeeScheduler)
{
using (Html.BeginForm("RedirectToDevExpressScheduler", "Main", FormMethod.Post))
{
<li class="nav-item">
<button class="btn btn-link text-light no-underline" onclick="showSpinner()">
<i class="far fa-calendar-alt text-bewo-calendar"></i>
DX Kalender
</button>
</li>
}
}
@if (Model.IsAllowedToSeePersons)
{

View File

@@ -1,7 +1,7 @@
INSERT INTO `.executedscripts`
VALUES ('Changes_2026-05-12 AiPromptbausteinRoutine Favoriten', CURDATE());
ALTER TABLE `aipromptbauteinroutine`
ALTER TABLE `aipromptbausteinroutine`
RENAME TO `aipromptbausteinroutine` ;
CREATE TABLE `aipromptbausteinroutine2empfavorite` (

View File

@@ -272,5 +272,9 @@ namespace BeWo.Service.ServiceContracts
[FaultContract(typeof(BeWoFault))]
[OperationContract]
Dictionary<DateTimeSpan, Dictionary<DateTime, bool>> FindAppointmentsInRangeForIntervalFinder(int duration, DateTime startDate, DateTime endDate, List<long> resourceOids, List<long> customerOids, List<long> employeeOids, long loggedInEmployeeOid, int intervalBuffer = 30, bool skipWeekends = true);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
List<SchedulerAppointmentDC> LoadFilteredAppointmentsMitAufgabenForMoK(bool pHasRightToSeeAllEmployeeAppointments, long pEmployeeOid, DateTime pIntervalStart, DateTime pIntervalEnd, List<long> pSelectedEmployees, List<long> pSelectedCustomer, List<long> pSelectedResources, bool pEmployeesOnly, bool pCustomersOnly, bool pResourcesOnly, bool pPrivateAppointmentsOnly, bool pOnlyMyAppointments, bool pShowTasks);
}
}

View File

@@ -1191,6 +1191,7 @@ namespace BeWo.Service.ServiceImplementations
ownerOid = pEmployeeOid;
}
// ToDo: Mit lokaler Variable arbeiten, weil sonst der angemeldete Mitarbeiter ignoriert wird!
if(!(!pHasRightToSeeAllEmployeeAppointments && pSelectedEmployees != null && pSelectedEmployees.Count == 1 && pSelectedEmployees.Contains(pEmployeeOid)))
{
//Rausnehmen, sonst werden Termine nicht gezeigt, bei denen man Owner ist und kein Employee ausgewählt wurde.
@@ -2982,5 +2983,168 @@ namespace BeWo.Service.ServiceImplementations
throw Utils.CreateBeWoFaultException(e);
}
}
public List<SchedulerAppointmentDC> LoadFilteredAppointmentsMitAufgabenForMoK(bool pHasRightToSeeAllEmployeeAppointments, long pEmployeeOid, DateTime pIntervalStart, DateTime pIntervalEnd, List<long> pSelectedEmployees, List<long> pSelectedCustomer, List<long> pSelectedResources, bool pEmployeesOnly, bool pCustomersOnly, bool pResourcesOnly, bool pPrivateAppointmentsOnly, bool pOnlyMyAppointments, bool pShowTasks)
{
try
{
long? ownerOid = null;
var selectedEmployees = new List<long>(pSelectedEmployees ?? new List<long>());
//Keine Auswahl getroffen: Nur meine Termine anzeigen
if(selectedEmployees?.Count == 0 && pSelectedCustomer?.Count == 0 && pSelectedResources?.Count == 0)
{
ownerOid = pEmployeeOid;
}
//Benutzer hat sich selber selektiert
if((bool) selectedEmployees?.Exists(e => e == pEmployeeOid))
{
ownerOid = pEmployeeOid;
}
//Man hat nur Customer und/oder Ressourcen ausgewählt, dann dürfen die eigenen nicht angezeigt werden
if(selectedEmployees?.Count == 0 &&
(pSelectedCustomer?.Count > 0 ||
pSelectedResources?.Count > 0))
{
ownerOid = null;
}
//Wenn man kein Recht hat alle zu sehen, muss immer auf Owner gefiltert werden, außer es sind Ressourcen vorhanden. Dann wird anonymisiert.
if(!pHasRightToSeeAllEmployeeAppointments && pSelectedResources?.Count == 0)
{
ownerOid = pEmployeeOid;
}
// ToDo: Mit lokaler Variable arbeiten, weil sonst der angemeldete Mitarbeiter ignoriert wird!
if(!(!pHasRightToSeeAllEmployeeAppointments && selectedEmployees.Count == 1 && selectedEmployees.Contains(pEmployeeOid)))
{
//Rausnehmen, sonst werden Termine nicht gezeigt, bei denen man Owner ist und kein Employee ausgewählt wurde.
//Wird nicht rausgenommen, wenn man die Termine anderer Mitarbeiter nicht sehen darf und "nur meine Termine" ausgewählt hat.
//Sonst werden die Filter mit and und nicht mit or verknüpft.
selectedEmployees?.Remove(pEmployeeOid);
}
if(pPrivateAppointmentsOnly && selectedEmployees?.Count == 0 && pSelectedCustomer?.Count == 0 && pSelectedResources?.Count == 0 && selectedEmployees?.Count != 0 &&
(pSelectedCustomer?.Count > 0 || pSelectedResources?.Count > 0))
{
ownerOid = pEmployeeOid;
}
var appointments = DAOFactory.SearchDAO.LoadFilteredAppointmentsForEmployee(pHasRightToSeeAllEmployeeAppointments, ownerOid, pIntervalStart, pIntervalEnd, selectedEmployees, pSelectedCustomer, pSelectedResources, pEmployeesOnly, pCustomersOnly, pResourcesOnly, pPrivateAppointmentsOnly, pOnlyMyAppointments, false).ToList();
var serientermine = appointments.Where(app => app.RecurrenceInfo != null && app.Type == 1).ToList();
var all = MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MapToNewDCs(appointments).OrderBy(a => a.StartDate).ToList();
var filteredEmployeeOids = new List<long>();
if(ownerOid.HasValue)
{
filteredEmployeeOids.Add(ownerOid.Value);
}
foreach(var empOid in selectedEmployees)
{
filteredEmployeeOids.Add(empOid);
}
var result = FilterAppointments(all, pEmployeeOid, filteredEmployeeOids, pSelectedCustomer, pSelectedResources, pCustomersOnly, pResourcesOnly, pShowTasks);
//Check fehlerhafte RecurrenceInfos
foreach(var app in result)
{
if(!IsNullOrEmpty(app.RecurrenceInfo))
{
if(app.RecurrenceInfo.Contains("WeekDays=\"0\""))
{
app.RecurrenceInfo = app.RecurrenceInfo.Replace("WeekDays=\"0\"", "WeekDays=\"2\"");
}
}
}
var test = result.Count;
// Ausnahmen immer laden. Entsprechen die Ausnahmen nicht den Filterkriterien, werden sie als gelöscht markiert, um nicht auf dem Client angezeigt zu werden.
var ausnahmen = MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MapToNewDCs(DAOFactory.SearchDAO.FindAppointmentsByRecurrenecInfo(result.Where(w => w.Type == 1).Select(s => s.RecurrenceInfo).ToList(), true));
var demFilterEntsprechendeTermine = FilterAppointments(ausnahmen, pEmployeeOid, filteredEmployeeOids, pSelectedCustomer, pSelectedResources, pCustomersOnly, pResourcesOnly, pShowTasks);
foreach(var appointment in ausnahmen.Where(w => !demFilterEntsprechendeTermine.Contains(w)))
{
var kosmetisch = new SchedulerAppointmentDC
{
SchedulerAppointmentOid = appointment.SchedulerAppointmentOid * -1,
NewSchedulerAppointmentVersion = 1,
Type = 4,
RecurrenceInfo = appointment.RecurrenceInfo,
EmployeeList = appointment.EmployeeList,
CustomerList = appointment.CustomerList,
ResourceList = appointment.ResourceList,
Originator = appointment.Originator
};
result.Add(kosmetisch);
}
UserDC user;
if(LoggedInUserOperationContextExt.Current != null && LoggedInUserOperationContextExt.Current.User != null)
{
user = MapperFactory.UserDC_User.MapToNewDC(LoggedInUserOperationContextExt.Current.User);
}
else
{
user = MapperFactory.UserDC_User.MapToNewDC(SessionFacade.LoggedInUser);
}
var appointmentsToCheckForAnonymization = new List<SchedulerAppointmentDC>();
var relatedCustomerOids = DAOFactory.SearchDAO.FindTeamRelatedCustomerOids(user.Employee.EmployeeOid);
if(!(user is null))
{
// Bei ausgewählten Ressourcen oder auch "Nur Ressourcen" werden auch Termine mit den ausgewählten Ressourcen geladen und anonymisiert angezeigt, die der angemeldete Mitarbeiter nicht sehen darf.
// ToDo: Hat man das Rechte "Alles Ansehen", wird nicht anonymisiert, da CheckSchedulerRights true zurückgibt!
//var hasRightToSeeAll = user.HasRight(UserRightType.ViewAll);
//appointmentsToCheckForAnonymization =
// pSelectedResources.Any() || pResourcesOnly ?
// result.Where(w =>
// w.ResourceList.Any() && false == SUtils.CheckSchedulerRights(w, SchedulerRightsCheckType.View, user, relatedCustomerOids, true)).ToList() :
// new List<SchedulerAppointmentDC>();
AnonymizeAppointments(result.Where(w => false == SUtils.CheckSchedulerRights(w, SchedulerRightsCheckType.View, user, relatedCustomerOids, true)).ToList());
if(pSelectedResources?.Any() ?? false)
{
AnonymizeAppointments(result.Where(appointment => appointment.ResourceList.Any()).ToList());
}
// Es wird nach zugewiesenen Rechten gefiltert und ob die Termine bereits in der Liste mit den anonymisierten Terminen sind.
//result = result.Where(w => (!w.ResourceList.Any() || SUtils.CheckSchedulerRights(w, SchedulerRightsCheckType.View, user, relatedCustomerOids, true)) && !appointmentsToCheckForAnonymization.Any(a => a.SchedulerAppointmentOid == w.SchedulerAppointmentOid)).ToList();
//result.AddRange(appointmentsToCheckForAnonymization);
}
// Aufgaben laden
ConvertOldTasks(pEmployeeOid);
var taskAppointmentDCs = MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MapToNewDCs(DAOFactory.SearchDAO.LoadTaskAppointmentsForEmployee(pEmployeeOid, true));
result.AddRangeIfElementsNotIn(taskAppointmentDCs);
//DebugUtils.WriteToLogFile($"{DateTime.Now:dd.MM.yyyy HH:mm:ss:fff}: {result.Count} Termine und {result.Count(w => w.IsTask)} Aufgaben aus der Datenbank geladen. {appointmentsToCheckForAnonymization.Count} davon anonymisiert.");
Debug.WriteLine($"+++>{DateTime.Now:dd.MM.yyyy HH:mm:ss:fff}: {result.Count} Termine und {result.Count(w => w.IsTask)} Aufgaben aus der Datenbank geladen. {appointmentsToCheckForAnonymization.Count} davon anonymisiert.");
// ToDo: durch jeden Termin gehen und prüfen, ob Klienten oder Mitarbeiter anonymisiert und auf read-only gesetzt werden müssen?
var appointmentsToBeAnonymized = result.Where(a => !SUtils.CheckSchedulerRights(a, SchedulerRightsCheckType.View, user, relatedCustomerOids, true)).ToList();
var rest = result.Except(appointmentsToBeAnonymized);
return result;
}
catch(Exception e)
{
throw Utils.CreateBeWoFaultException(e);
}
}
}
}

View File

@@ -65,7 +65,7 @@ namespace BeWoDatabaseUpdater
Console.WriteLine($"{DateTime.Now:dd.MM.yyyy HH:mm:ss.fff}: Führe Updates durch ...{Environment.NewLine}");
_BeWoSchemaNames = await MySqlBeWoHelper.LoadBeWoDatabaseNames(_ConnectionString) ?? [];
_BeWoSchemaNames = ["3522103738"]; //await MySqlBeWoHelper.LoadBeWoDatabaseNames(_ConnectionString) ?? [];
LoadSqlScriptsFromFilesToMemory(() =>
{
@@ -74,6 +74,11 @@ namespace BeWoDatabaseUpdater
_FilePaths2Sql.DoForEach(path2Commands =>
{
if(path2Commands is null)
{
return;
}
commandCount += path2Commands.Commands.Count;
fileCount++;
});
@@ -160,6 +165,8 @@ namespace BeWoDatabaseUpdater
//MySqlBeWoHelper.WriteSqlErrorsToFile();
MySqlBeWoHelper.DistinctErrors.DoForEach(number2Message => Console.WriteLine($"{number2Message.Key}: {number2Message.Value}"));
Console.WriteLine("Alle Updates durchgeführt!");
}
private static void GetTextAndSqlFiles()