Explorar o código

Editieren von Kommentaren + Plugin-Handling fertiggestellt!

Arne Diekmann %!s(int64=8) %!d(string=hai) anos
pai
achega
753c58109c
Modificáronse 32 ficheiros con 877 adicións e 159 borrados
  1. 1 1
      GreenTree.Nachtragsmanagement.Core/Plugins/PluginExtensions.cs
  2. 1 1
      GreenTree.Nachtragsmanagement.Plugin.Test/Controllers/TestController.cs
  3. 2 0
      GreenTree.Nachtragsmanagement.Plugin.Test/GreenTree.Nachtragsmanagement.Plugin.Test.csproj
  4. 18 0
      GreenTree.Nachtragsmanagement.Plugin.Test/Properties/PublishProfiles/FolderProfile.pubxml
  5. 1 1
      GreenTree.Nachtragsmanagement.Plugin.Test/Web.config
  6. 21 0
      GreenTree.Nachtragsmanagement.Services/Appendix/AppendixService.cs
  7. 5 0
      GreenTree.Nachtragsmanagement.Services/Appendix/IAppendixService.cs
  8. 24 0
      GreenTree.Nachtragsmanagement.Services/Deviation/DeviationService.cs
  9. 5 0
      GreenTree.Nachtragsmanagement.Services/Deviation/IDeviationService.cs
  10. 5 0
      GreenTree.Nachtragsmanagement.Services/Site/ISiteService.cs
  11. 21 0
      GreenTree.Nachtragsmanagement.Services/Site/SiteService.cs
  12. 1 0
      GreenTree.Nachtragsmanagement.Web/App_Data/InstalledPlugins.txt
  13. 8 0
      GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs
  14. 90 49
      GreenTree.Nachtragsmanagement.Web/Controllers/AdminController.cs
  15. 9 3
      GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs
  16. 9 3
      GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs
  17. 91 0
      GreenTree.Nachtragsmanagement.Web/Controllers/GlobalController.cs
  18. 9 3
      GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs
  19. 164 46
      GreenTree.Nachtragsmanagement.Web/Extensions/GridViewSettingsHelper.cs
  20. 4 0
      GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj
  21. 37 0
      GreenTree.Nachtragsmanagement.Web/Models/Admin/Plugins/PluginDataModel.cs
  22. 14 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/EditEntityCommentModel.cs
  23. 1 1
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Description.txt
  24. BIN=BIN
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll
  25. 15 19
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll.config
  26. 0 0
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Views/Home/Index.cshtml
  27. 16 25
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Web.config
  28. 0 0
      GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/logo.jpg
  29. 103 2
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Plugins/View.cshtml
  30. 107 0
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Plugins/_PluginsGridPartial.cshtml
  31. 82 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_EditCommentPartial.cshtml
  32. 13 5
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_FunctionLayout.cshtml

+ 1 - 1
GreenTree.Nachtragsmanagement.Core/Plugins/PluginExtensions.cs

@@ -33,7 +33,7 @@ namespace GreenTree.Nachtragsmanagement.Core.Plugins
                 return null;
             }
 
-            string logoUrl = string.Format("~/plugins/{1}/logo.jpg", pluginDirectory.Name);
+            string logoUrl = string.Format("~/plugins/{0}/logo.jpg", pluginDirectory.Name);
             return logoUrl;
         }
 

+ 1 - 1
GreenTree.Nachtragsmanagement.Plugin.Test/Controllers/TestController.cs

@@ -24,7 +24,7 @@ namespace GreenTree.Nachtragsmanagement.Plugin.Test.Controllers
         // GET: Home
         public ActionResult Index()
         {
-            return View("~/Plugins/Misc.Test/Views/Home/Index.cshtml");
+            return View("~/Plugins/Allgemein.Test/Views/Home/Index.cshtml");
         }
     }
 }

+ 2 - 0
GreenTree.Nachtragsmanagement.Plugin.Test/GreenTree.Nachtragsmanagement.Plugin.Test.csproj

@@ -23,6 +23,7 @@
     <UseGlobalApplicationHostFile />
     <NuGetPackageImportStamp>
     </NuGetPackageImportStamp>
+    <Use64BitIISExpress />
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -117,6 +118,7 @@
     <Content Include="Views\Home\Index.cshtml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

+ 18 - 0
GreenTree.Nachtragsmanagement.Plugin.Test/Properties/PublishProfiles/FolderProfile.pubxml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Diese Datei wird vom Veröffentlichungs-/Paketierungsprozess Ihres Webprojekts verwendet. Sie können das Verhalten dieses Prozesses anpassen,
+indem Sie diese MSBuild-Datei bearbeiten. Weitere Informationen hierzu finden Sie unter https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>FileSystem</WebPublishMethod>
+    <PublishProvider>FileSystem</PublishProvider>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish />
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <publishUrl>..\GreenTree.Nachtragsmanagement.Web\Plugins\Misc.Test</publishUrl>
+    <DeleteExistingFiles>False</DeleteExistingFiles>
+  </PropertyGroup>
+</Project>

+ 1 - 1
GreenTree.Nachtragsmanagement.Plugin.Test/Web.config

@@ -35,7 +35,7 @@
   <system.webServer>
     <handlers>
       <remove name="BlockViewHandler" />
-      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+      <add name="BlockViewHandler" path="~/Views/*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
     </handlers>
   </system.webServer>
   <runtime>

+ 21 - 0
GreenTree.Nachtragsmanagement.Services/Appendix/AppendixService.cs

@@ -49,6 +49,27 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
             return _appendixRepository.Table.ToList();
         }
 
+        /// <summary>
+        /// Gets all appendices where the user is assigned to the corresponding site if the current role only allows assigned sites
+        /// </summary>
+        public IList<Core.Domain.Appendix.Appendix> GetAllUserAssignedAppendices(Core.Domain.User.User user)
+        {
+            if (user == null || (user != null && user.CurrentRole == null))
+                return new List<Core.Domain.Appendix.Appendix>();
+
+            if (user.CurrentRole.SeeOnlyAssigned)
+            {
+                return
+                    _appendixRepository.Table
+                        .Where(a => a.Site != null && a.Site.Users
+                            .Select(u => u.Id).Contains(user.Id))
+                        .ToList();
+            }
+            else
+                return GetAllAppendices();
+
+        }
+
         /// <summary>
         /// Gets a appendix by specified Id
         /// </summary>

+ 5 - 0
GreenTree.Nachtragsmanagement.Services/Appendix/IAppendixService.cs

@@ -17,6 +17,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
         /// </summary>
         IList<Core.Domain.Appendix.Appendix> GetAllAppendices();
 
+        /// <summary>
+        /// Gets all appendices where the user is assigned to the corresponding site if the current role only allows assigned sites
+        /// </summary>
+        IList<Core.Domain.Appendix.Appendix> GetAllUserAssignedAppendices(Core.Domain.User.User user);
+
         /// <summary>
         /// Gets a appendix by specified Id
         /// </summary>

+ 24 - 0
GreenTree.Nachtragsmanagement.Services/Deviation/DeviationService.cs

@@ -48,6 +48,30 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
             return _deviationRepository.Table.ToList();
         }
 
+        /// <summary>
+        /// Gets all deviations where the user is assigned to the corresponding site if the current role only allows assigned sites
+        /// </summary>
+        public IList<Core.Domain.Deviation.Deviation> GetAllUserAssignedDeviations(Core.Domain.User.User user)
+        {
+            if (user == null || (user != null && user.CurrentRole == null))
+                return new List<Core.Domain.Deviation.Deviation>();
+
+            if (user.CurrentRole.SeeOnlyAssigned)
+            {
+                return
+                    _deviationRepository.Table
+                        .Where(d => 
+                            (d.Site != null && d.Site.Users
+                                .Select(u => u.Id).Contains(user.Id)) ||
+                            (d.Appendix != null && d.Appendix.Site != null && d.Appendix.Site.Users
+                                .Select(u => u.Id).Contains(user.Id)))
+                        .ToList();
+            }
+            else
+                return GetAllDeviations();
+
+        }
+
         /// <summary>
         /// Gets a deviation by specified Id
         /// </summary>

+ 5 - 0
GreenTree.Nachtragsmanagement.Services/Deviation/IDeviationService.cs

@@ -16,6 +16,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// </summary>
         IList<Core.Domain.Deviation.Deviation> GetAllDeviations();
 
+        /// <summary>
+        /// Gets all deviations where the user is assigned to the corresponding site if the current role only allows assigned sites
+        /// </summary>
+        IList<Core.Domain.Deviation.Deviation> GetAllUserAssignedDeviations(Core.Domain.User.User user);
+
         /// <summary>
         /// Gets a deviation by specified Id
         /// </summary>

+ 5 - 0
GreenTree.Nachtragsmanagement.Services/Site/ISiteService.cs

@@ -15,6 +15,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Site
         /// </summary>
         IList<Core.Domain.Site.Site> GetAllSites();
 
+        /// <summary>
+        /// Gets all sites where the user is assigned to if the current role only allows assigned sites
+        /// </summary>
+        IList<Core.Domain.Site.Site> GetAllUserAssignedSites(Core.Domain.User.User user);
+
         /// <summary>
         /// Gets a site by specified Id
         /// </summary>

+ 21 - 0
GreenTree.Nachtragsmanagement.Services/Site/SiteService.cs

@@ -38,6 +38,27 @@ namespace GreenTree.Nachtragsmanagement.Services.Site
             return _siteRepository.Table.ToList();
         }
 
+        /// <summary>
+        /// Gets all sites where the user is assigned to if the current role only allows assigned sites
+        /// </summary>
+        public IList<Core.Domain.Site.Site> GetAllUserAssignedSites(Core.Domain.User.User user)
+        {
+            if (user == null || (user != null && user.CurrentRole == null))
+                return new List<Core.Domain.Site.Site>();
+
+            if (user.CurrentRole.SeeOnlyAssigned)
+            {
+                return
+                    _siteRepository.Table
+                        .Where(s => s.Users
+                            .Select(u => u.Id).Contains(user.Id))
+                        .ToList();
+            }
+            else
+                return GetAllSites();
+                           
+        }
+
         /// <summary>
         /// Gets a site by specified Id
         /// </summary>

+ 1 - 0
GreenTree.Nachtragsmanagement.Web/App_Data/InstalledPlugins.txt

@@ -0,0 +1 @@
+GreenTree.Nachtragsmanagement.Test

+ 8 - 0
GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs

@@ -135,6 +135,14 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                     AllowMaximize = true
                 },
                 new Function
+                {
+                    Name = "Administration-Plugins-Edit",
+                    Description = "Plugins installieren / deinstallieren",
+                    GroupName = "Administration-Plugins",
+                    IsMenuMember = false,
+                    Plugin = "System"
+                },
+                new Function
                 {
                     Name = "Site",
                     Description = "Baustellen",

+ 90 - 49
GreenTree.Nachtragsmanagement.Web/Controllers/AdminController.cs

@@ -12,6 +12,7 @@ using GreenTree.Nachtragsmanagement.Core;
 using GreenTree.Nachtragsmanagement.Core.Plugins;
 using GreenTree.Nachtragsmanagement.Web.Framework.Authorization;
 using GreenTree.Nachtragsmanagement.Services.Logging;
+using GreenTree.Nachtragsmanagement.Web.Models.Admin.Plugins;
 
 namespace GreenTree.Nachtragsmanagement.Web.Controllers
 {
@@ -21,17 +22,20 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         private readonly IUserHelper _userHelper;
         private readonly IPluginFinder _pluginFinder;
         private readonly ILogger _logger;
+        private readonly IWebHelper _webHelper;
 
         public AdminController(
             IUserService userService,
             IUserHelper userHelper,
             IPluginFinder pluginFinder,
-            ILogger logger)
+            ILogger logger,
+            IWebHelper webHelper)
         {
             _userService = userService;
             _userHelper = userHelper;
             _pluginFinder = pluginFinder;
             _logger = logger;
+            _webHelper = webHelper;
 
             ViewData["AllRoles"] = _userService.GetAllRoles();
             ViewData["AllFunctions"] = _userService.GetAllFunctions();
@@ -371,69 +375,106 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
         #region Plugins
 
-        ///// <summary>
-        ///// Basic plugin view function
-        ///// </summary>
-        //public ActionResult ViewPlugins()
-        //{
-        //    var model = new PluginModel
-        //    {
-        //        PluginNames = new List<string[]>()
-        //    };
+        /// <summary>
+        /// Basic plugin view function
+        /// </summary>
+        public ActionResult ViewPlugins()
+        {
+            var plugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.All);
+            var pluginModels = plugins
+                .Select(p => PluginDataModel.FromPluginDesciptor(p.PluginDescriptor, _webHelper))
+                .ToList();
 
-        //    var uninstalledPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.NotInstalledOnly);
-        //    var installedPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.InstalledOnly);
+            return View("~/Views/Admin/Plugins/View.cshtml", pluginModels);
+        }
 
-        //    if (installedPlugins.Any())
-        //        model.PluginNames.AddRange(new List<string[]>()
-        //        {
-        //            new [] { installedPlugins.First().PluginDescriptor.SystemName, "installed" }
-        //        });
+        /// <summary>
+        /// Callback result for plugin grid
+        /// </summary>
+        /// <param name="scrollHeight">The height of the grid scrollable component.</param>
+        public ActionResult PartialPlugins(int scrollHeight = -1)
+        {
+            var plugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.All);
+            var pluginModels = plugins
+                .Select(p => PluginDataModel.FromPluginDesciptor(p.PluginDescriptor, _webHelper))
+                .ToList();
 
-        //    if (uninstalledPlugins.Any())
-        //        model.PluginNames.AddRange(new List<string[]>()
-        //        {
-        //            new [] { uninstalledPlugins.First().PluginDescriptor.SystemName, "uninstalled" }
-        //        });
+            ViewData["ScrollHeight"] = scrollHeight;
 
-        //    return View("~/Views/Admin/Plugins/View.cshtml");
-        //}
+            return View("~/Views/Admin/Plugins/_PluginsGridPartial.cshtml", pluginModels);
+        }
 
-        //[HttpPost]
-        //public ActionResult InstallPlugin(string pluginName)
-        //{
-        //    var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
-        //    if (pluginDescriptor == null)
-        //        return RedirectToAction("Plugins");
+        /// <summary>
+        /// Installs a plugin
+        /// </summary>
+        /// <param name="pluginName">SystemName of plugin.</param>
+        [HttpPost]
+        public ActionResult InstallPlugin(string pluginName)
+        {
+            try
+            {
+                var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
+                if (pluginDescriptor == null)
+                    return RedirectToAction("Plugins");
 
-        //    if (pluginDescriptor.Installed)
-        //        return RedirectToAction("Plugins");
+                if (pluginDescriptor.Installed)
+                    return RedirectToAction("Plugins");
 
-        //    var routes = System.Web.Routing.RouteTable.Routes;
+                pluginDescriptor.Instance().Install();
 
-        //    pluginDescriptor.Instance().Install();
+                _logger.Information(String.Format("Plugin \"{0}\" erfolgreich installiert.", pluginName));
 
-        //    _webHelper.RestartAppDomain();
+                _webHelper.RestartAppDomain();
 
-        //    return RedirectToAction("Plugins");
-        //}
+                return new JsonResult
+                {
+                    Data = "success"
+                };
+            }
+            catch (Exception ex)
+            {
+                _logger.Error(
+                    String.Format("Fehler bei der Installation des Plugin \"{0}\".", pluginName), ex);
+
+                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
+            }
+        }
+
+        /// <summary>
+        /// Uninstalls a plugin
+        /// </summary>
+        /// <param name="pluginName">SystemName of plugin.</param>
+        [HttpPost]
+        public ActionResult UninstallPlugin(string pluginName)
+        {
+            try
+            {
+                var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
+                if (pluginDescriptor == null)
+                    return RedirectToAction("Plugins");
 
-        //[HttpPost]
-        //public ActionResult UninstallPlugin(string pluginName)
-        //{
-        //    var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
-        //    if (pluginDescriptor == null)
-        //        return RedirectToAction("Plugins");
+                if (!pluginDescriptor.Installed)
+                    return RedirectToAction("Plugins");
 
-        //    if (!pluginDescriptor.Installed)
-        //        return RedirectToAction("Plugins");
+                pluginDescriptor.Instance().Uninstall();
 
-        //    pluginDescriptor.Instance().Uninstall();
+                _logger.Information(String.Format("Plugin \"{0}\" erfolgreich deinstalliert.", pluginName));
 
-        //    _webHelper.RestartAppDomain();
+                _webHelper.RestartAppDomain();
 
-        //    return RedirectToAction("Plugins");
-        //}
+                return new JsonResult
+                {
+                    Data = "success"
+                };
+            }
+            catch (Exception ex)
+            {
+                _logger.Error(
+                    String.Format("Fehler bei der Installation des Plugin \"{0}\".", pluginName), ex);
+
+                return PartialView("~/Views/Shared/_PopupError.cshtml", ex);
+            }
+        }
 
         #endregion
     }

+ 9 - 3
GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs

@@ -51,7 +51,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         [FunctionAuthorize(true, "Appendix-Appendices")]
         public ActionResult ViewAppendices()
         {
-            var appendices = _appendixService.GetAllAppendices();
+            var currentUser = _userHelper.FromCookies();
+
+            var appendices = _appendixService.GetAllUserAssignedAppendices(currentUser);
             var appendixModels = appendices
                 .Select(u => AppendixDataModel.FromAppendix(u, false))
                 .ToList();
@@ -87,7 +89,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// </summary>
         public ActionResult PartialAppendices(int scrollHeight = -1)
         {
-            var appendices = _appendixService.GetAllAppendices();
+            var currentUser = _userHelper.FromCookies();
+
+            var appendices = _appendixService.GetAllUserAssignedAppendices(currentUser);
             var appendixModels = appendices
                 .Select(u => AppendixDataModel.FromAppendix(u, false))
                 .ToList();
@@ -106,7 +110,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             if (exportformat == null || String.IsNullOrEmpty(exportformat.Format))
                 return new EmptyResult();
 
-            var appendices = _appendixService.GetAllAppendices();
+            var currentUser = _userHelper.FromCookies();
+
+            var appendices = _appendixService.GetAllUserAssignedAppendices(currentUser);
             var appendixModels = appendices
                 .Select(u => AppendixDataModel.FromAppendix(u, false))
                 .ToList();

+ 9 - 3
GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs

@@ -53,7 +53,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         [FunctionAuthorize(true, "Deviation-Deviations")]
         public ActionResult ViewDeviations()
         {
-            var deviations = _deviationService.GetAllDeviations();
+            var currentUser = _userHelper.FromCookies();
+
+            var deviations = _deviationService.GetAllUserAssignedDeviations(currentUser);
             var deviationModels = deviations
                 .Select(u => DeviationDataModel.FromDeviation(u, false))
                 .ToList();
@@ -90,7 +92,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// <param name="scrollHeight">The height of the grid scrollable component.</param>
         public ActionResult PartialDeviations(int scrollHeight = -1)
         {
-            var deviations = _deviationService.GetAllDeviations();
+            var currentUser = _userHelper.FromCookies();
+
+            var deviations = _deviationService.GetAllUserAssignedDeviations(currentUser);
             var deviationModels = deviations
                 .Select(u => DeviationDataModel.FromDeviation(u, false))
                 .ToList();
@@ -109,7 +113,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             if (exportformat == null || String.IsNullOrEmpty(exportformat.Format))
                 return new EmptyResult();
 
-            var deviations = _deviationService.GetAllDeviations();
+            var currentUser = _userHelper.FromCookies();
+
+            var deviations = _deviationService.GetAllUserAssignedDeviations(currentUser);
             var deviationModels = deviations
                 .Select(u => DeviationDataModel.FromDeviation(u, false))
                 .ToList();

+ 91 - 0
GreenTree.Nachtragsmanagement.Web/Controllers/GlobalController.cs

@@ -107,6 +107,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             return View("~/Views/Global/NotAuthorized.cshtml");
         }
 
+        #region Comments
+
         /// <summary>
         /// Gets a full comment of a given entity
         /// </summary>
@@ -146,5 +148,94 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
             return result;
         }
+
+        /// <summary>
+        /// Gets a full comment of a given entity and provides an edit form
+        /// </summary>
+        /// <param name="entityType">The entity type.</param>
+        /// <param name="id">The entity id.</param>
+        public ActionResult EditEntityComment(string entityType, int id)
+        {
+            var editCommentModel = new EditEntityCommentModel
+            {
+                EntityType = entityType,
+                EntityId = id
+            };
+
+            switch (entityType)
+            {
+                case "appendix":
+                    var appendix = _appendixService.GetAppendixById(id);
+
+                    editCommentModel.Comment = appendix.Comment;
+                    break;
+                case "deviation":
+                    var deviation = _deviationService.GetDeviationById(id);
+
+                    editCommentModel.Comment = deviation.Comment;
+                    break;
+                case "site":
+                    var site = _siteService.GetSiteById(id);
+
+                    editCommentModel.Comment = site.Comment;
+                    break;
+                default:
+                    return new EmptyResult();
+            }
+
+            return PartialView("~/Views/Shared/_EditCommentPartial.cshtml", editCommentModel);
+        }
+
+        /// <summary>
+        /// Sets a comment for a given entity
+        /// </summary>
+        /// <param name="entityType">The entity type.</param>
+        /// <param name="id">The entity id.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditEntityComment(EditEntityCommentModel model)
+        {
+            if (model == null)
+                return new EmptyResult();
+
+            switch (model.EntityType)
+            {
+                case "appendix":
+                    var appendix = _appendixService.GetAppendixById(model.EntityId);
+
+                    appendix.Comment = model.Comment;
+
+                    _appendixService.UpdateAppendix(appendix);
+
+                    _logger.Entity(appendix, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookies());
+                    break;
+                case "deviation":
+                    var deviation = _deviationService.GetDeviationById(model.EntityId);
+
+                    deviation.Comment = model.Comment;
+
+                    _deviationService.UpdateDeviation(deviation);
+
+                    _logger.Entity(deviation, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookies());
+                    break;
+                case "site":
+                    var site = _siteService.GetSiteById(model.EntityId);
+
+                    site.Comment = model.Comment;
+
+                    _siteService.UpdateSite(site);
+
+                    _logger.Entity(site, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookies());
+                    break;
+                default:
+                    return new EmptyResult();
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        #endregion
     }
 }

+ 9 - 3
GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs

@@ -72,7 +72,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         [FunctionAuthorize(true, "Site-Sites")]
         public ActionResult ViewSites()
         {
-            var sites = _siteService.GetAllSites();
+            var currentUser = _userHelper.FromCookies();
+
+            var sites = _siteService.GetAllUserAssignedSites(currentUser);
             var siteModels = sites
                 .Select(u => SiteDataModel.FromSite(u, false))
                 .ToList();
@@ -112,7 +114,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// <param name="scrollHeight">The height of the grid scrollable component.</param>
         public ActionResult PartialSites(int scrollHeight = -1)
         {
-            var sites = _siteService.GetAllSites();
+            var currentUser = _userHelper.FromCookies();
+
+            var sites = _siteService.GetAllUserAssignedSites(currentUser);
             var siteModels = sites
                 .Select(u => SiteDataModel.FromSite(u, false))
                 .ToList();
@@ -131,7 +135,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             if (exportformat == null || String.IsNullOrEmpty(exportformat.Format))
                 return new EmptyResult();
 
-            var sites = _siteService.GetAllSites();
+            var currentUser = _userHelper.FromCookies();
+
+            var sites = _siteService.GetAllUserAssignedSites(currentUser);
             var siteModels = sites
                 .Select(u => SiteDataModel.FromSite(u, false))
                 .ToList();

+ 164 - 46
GreenTree.Nachtragsmanagement.Web/Extensions/GridViewSettingsHelper.cs

@@ -216,25 +216,52 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                     var text = comment == null
                         ? String.Empty
                         : comment.ToString();
+                    var isLongText = text.ToString().Length > 40;
 
-                    if (text.ToString().Length > 40)
+                    if (isLongText)
                     {
                         html.ViewContext.Writer.Write(text.Substring(0, 40) + " ...");
-                        html.ViewContext.Writer.Write("<a href=\"#\" onclick='showComment(\"site\"," + id + ",this)'><br />Anzeigen</a>");
+                        html.ViewContext.Writer.Write(
+                            "<a href=\"#\" onclick='showComment(\"site\"," + id + ",this)'><br />Anzeigen</a>");
                     }
                     else
                         html.ViewContext.Writer.Write(text);
+
+                    if (_userContext.CurrentUser.HasFunction("Site-Sites-Edit"))
+                        html.ViewContext.Writer.Write(
+                            (isLongText ? "&nbsp;" : "<br/>") +
+                            "<a href=\"#\" onclick='editComment(\"site\"," + id + ",function() { devGridViewSite.PerformCallback(); })'>Bearbeiten</a>");
                 });
                 column.MinWidth = 120;
                 column.Width = new Unit(15, UnitType.Percentage);
                 column.Visible = false;
             });
 
-            s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Sum, "DeviationValue");
-            s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "DeviationValue");
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl<br/><i>{0:n0}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl = {0:n0}"
+            });
 
-            s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
-            s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "DeviationValue",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "VA ∑<br/><i>{0:c2}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "DeviationValue",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "VA ∑ = <i>{0:c2}</i>"
+            });
 
             s.ClientLayout = (sender, e) =>
             {
@@ -275,6 +302,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.Settings.ShowFooter = true;
             s.Settings.ShowGroupPanel = true;
             s.Settings.AutoFilterCondition = AutoFilterCondition.Contains;
+            s.Settings.HorizontalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollableHeight =
                 (html.ViewData["ScrollHeight"] == null || (int)html.ViewData["ScrollHeight"] == -1)
@@ -287,7 +315,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.SettingsBehavior.EnableCustomizationWindow = true;
             s.SettingsBehavior.AllowHeaderFilter = true;
             s.SettingsPager.AlwaysShowPager = true;
-            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.NextColumn;
+            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.Control;
             s.SettingsCookies.Enabled = true;
             s.SettingsCookies.CookiesID = "deviationGridStateCookie";
 
@@ -336,31 +364,31 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
 
             s.Columns.Add(column =>
             {
-                column.Caption = "Nummer";
+                column.Caption = "Nr.";
                 column.FieldName = "CustomNumber";
-                column.MinWidth = 80;
-                column.Width = new Unit(8, UnitType.Percentage);
+                column.MinWidth = 50;
+                column.Width = new Unit(60, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
                 column.Caption = "Bezeichnung";
                 column.FieldName = "Description";
-                column.MinWidth = 200;
-                column.Width = new Unit(14, UnitType.Percentage);
+                column.MinWidth = 220;
+                column.Width = new Unit(250, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
-                column.Caption = "Baustelle";
+                column.Caption = "Kst.-Stelle";
                 column.FieldName = "SiteDescription";
                 column.MinWidth = 120;
-                column.Width = new Unit(10, UnitType.Percentage);
+                column.Width = new Unit(130, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
                 column.Caption = "Nachtrag";
                 column.FieldName = "AppendixDescription";
-                column.MinWidth = 120;
-                column.Width = new Unit(10, UnitType.Percentage);
+                column.MinWidth = 100;
+                column.Width = new Unit(100, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
@@ -369,14 +397,31 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                 column.PropertiesEdit.DisplayFormatString = "dd.MM.yyyy";
                 column.SettingsHeaderFilter.Mode = GridHeaderFilterMode.DateRangePicker;
                 column.MinWidth = 110;
-                column.Width = new Unit(8, UnitType.Percentage);
+                column.Width = new Unit(110, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
-                column.Caption = "Tage VA - NT";
+                column.Caption = "Tage VA-NT";
                 column.FieldName = "DaysReceiptToAppendixOffering";
-                column.MinWidth = 110;
-                column.Width = new Unit(8, UnitType.Percentage);
+                column.MinWidth = 100;
+                column.Width = new Unit(110, UnitType.Pixel);
+                column.HeaderStyle.Wrap = DefaultBoolean.True;
+            });
+            s.Columns.Add(column =>
+            {
+                column.Caption = "Schätzung";
+                column.FieldName = "Value";
+                column.PropertiesEdit.DisplayFormatString = "c2";
+                column.MinWidth = 100;
+                column.Width = new Unit(120, UnitType.Pixel);
+            });
+            s.Columns.Add(column =>
+            {
+                column.Caption = "Bewert.";
+                column.FieldName = "Percentage";
+                column.PropertiesEdit.DisplayFormatString = "p0";
+                column.MinWidth = 70;
+                column.Width = new Unit(80, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
@@ -384,28 +429,29 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                 column.FieldName = "PercentageValue";
                 column.PropertiesEdit.DisplayFormatString = "c2";
                 column.MinWidth = 100;
-                column.Width = new Unit(9, UnitType.Percentage);
+                column.Width = new Unit(120, UnitType.Pixel);
+                column.HeaderStyle.Wrap = DefaultBoolean.True;
             });
             s.Columns.Add(column =>
             {
                 column.Caption = "Status";
                 column.FieldName = "StatusDescription";
-                column.MinWidth = 160;
-                column.Width = new Unit(12, UnitType.Percentage);
+                column.MinWidth = 110;
+                column.Width = new Unit(120, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
                 column.Caption = "VA-Kategorien";
                 column.FieldName = "DisturbanceValuesDescription";
-                column.MinWidth = 200;
-                column.Width = new Unit(14, UnitType.Percentage);
+                column.MinWidth = 190;
+                column.Width = new Unit(220, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
                 column.Caption = "Art";
                 column.FieldName = "KindDescription";
                 column.MinWidth = 140;
-                column.Width = new Unit(10, UnitType.Percentage);
+                column.Width = new Unit(140, UnitType.Pixel);
             });
             s.Columns.Add(column =>
             {
@@ -420,14 +466,21 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                     var text = comment == null
                         ? String.Empty
                         : comment.ToString();
+                    var isLongText = text.ToString().Length > 40;
 
-                    if (text.ToString().Length > 40)
+                    if (isLongText)
                     {
                         html.ViewContext.Writer.Write(text.Substring(0, 40) + " ...");
-                        html.ViewContext.Writer.Write("<a href=\"#\" onclick='showComment(\"deviation\"," + id + ",this)'><br />Anzeigen</a>");
+                        html.ViewContext.Writer.Write(
+                            "<a href=\"#\" onclick='showComment(\"deviation\"," + id + ",this)'><br />Anzeigen</a>");
                     }
                     else
                         html.ViewContext.Writer.Write(text);
+
+                    if (_userContext.CurrentUser.HasFunction("Deviation-Deviations-Edit"))
+                        html.ViewContext.Writer.Write(
+                            (isLongText ? "&nbsp;" : "<br/>") +
+                            "&nbsp;<a href=\"#\" onclick='editComment(\"deviation\"," + id + ",function() { devGridViewDeviation.PerformCallback(); })'>Bearbeiten</a>");
                 });
                 column.MinWidth = 120;
                 column.Width = new Unit(8, UnitType.Percentage);
@@ -460,23 +513,69 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                     e.TotalValue = totalDaysReceiptToAppendixOfferingSum / totalDaysReceiptToAppendixOfferingCount;
             };
 
-            s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");
-            s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl<br/><i>{0:n0}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl = {0:n0}"
+            });
+
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "Value",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "Schätzung ∑<br/><i>{0:c2}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "Value",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "Schätzung ∑ = <i>{0:c2}</i>"
+            });
+
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "Percentage",
+                SummaryType = DevExpress.Data.SummaryItemType.Average,
+                DisplayFormat = "Bew. Ø<br/><i>{0:p0}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "Percentage",
+                SummaryType = DevExpress.Data.SummaryItemType.Average,
+                DisplayFormat = "Bew. Ø = <i>{0:p0}</i>"
+            });
 
-            s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
-            s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "PercentageValue",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "Schätz. bew. ∑<br/><i>{0:c2}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                FieldName = "PercentageValue",
+                SummaryType = DevExpress.Data.SummaryItemType.Sum,
+                DisplayFormat = "Schätz. bew. ∑ = <i>{0:c2}</i>"
+            });
 
             s.TotalSummary.Add(new ASPxSummaryItem
             {
                 FieldName = "DaysReceiptToAppendixOffering",
                 SummaryType = DevExpress.Data.SummaryItemType.Custom,
-                DisplayFormat = "Schnitt = {0:n0}"
+                DisplayFormat = "T. VA-NT Ø<br/><i>{0:n0}</i>"
             });
             s.GroupSummary.Add(new ASPxSummaryItem
             {
                 FieldName = "DaysReceiptToAppendixOffering",
                 SummaryType = DevExpress.Data.SummaryItemType.Custom,
-                DisplayFormat = "Schnitt = {0:n0}"
+                DisplayFormat = "Tage VA-NT Ø = <i>{0:n0}</i>"
             });
 
             s.ClientLayout = (sender, e) =>
@@ -684,46 +783,63 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
                     var text = comment == null
                         ? String.Empty
                         : comment.ToString();
+                    var isLongText = text.ToString().Length > 40;
 
-                    if (text.ToString().Length > 40)
+                    if (isLongText)
                     {
                         html.ViewContext.Writer.Write(text.Substring(0, 40) + " ...");
-                        html.ViewContext.Writer.Write("<a href=\"#\" onclick='showComment(\"appendix\"," + id + ",this)'><br />Anzeigen</a>");
+                        html.ViewContext.Writer.Write(
+                            "<a href=\"#\" onclick='showComment(\"appendix\"," + id + ",this)'><br />Anzeigen</a>");
                     }
                     else
                         html.ViewContext.Writer.Write(text);
+
+                    if (_userContext.CurrentUser.HasFunction("Deviation-Deviations-Edit"))
+                        html.ViewContext.Writer.Write(
+                            (isLongText ? "&nbsp;" : "<br/>") +
+                            "<a href=\"#\" onclick='editComment(\"appendix\"," + id + ",function() { devGridViewAppendix.PerformCallback(); })'>Bearbeiten</a>");
                 });
                 column.MinWidth = 250;
                 column.Width = new Unit(14, UnitType.Percentage);
             });
 
-            s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
-            s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Count, "CustomNumber");
+            s.TotalSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl<br/><i>{0:n0}</i>"
+            });
+            s.GroupSummary.Add(new ASPxSummaryItem
+            {
+                SummaryType = DevExpress.Data.SummaryItemType.Count,
+                FieldName = "Description",
+                DisplayFormat = "Anzahl = {0:n0}"
+            });
 
             s.TotalSummary.Add(new ASPxSummaryItem
             {
                 SummaryType = DevExpress.Data.SummaryItemType.Sum,
                 FieldName = "OfferingValue",
-                DisplayFormat = "Angeb.-Sum.: {0:c2}"
+                DisplayFormat = "Angeb. ∑<br/><i>{0:c2}</i>"
             });
             s.GroupSummary.Add(new ASPxSummaryItem
             {
                 SummaryType = DevExpress.Data.SummaryItemType.Sum,
                 FieldName = "OfferingValue",
-                DisplayFormat = "Angeb.-Sum.: {0:c2}"
+                DisplayFormat = "Angeb.-∑ = {0:c2}"
             });
 
             s.TotalSummary.Add(new ASPxSummaryItem
             {
                 SummaryType = DevExpress.Data.SummaryItemType.Sum,
                 FieldName = "NegotiationValue",
-                DisplayFormat = "Verhand.-Sum.: {0:c2}"
+                DisplayFormat = "Verhand. ∑<br/><i>{0:c2}</i>"
             });
             s.GroupSummary.Add(new ASPxSummaryItem
             {
                 SummaryType = DevExpress.Data.SummaryItemType.Sum,
                 FieldName = "NegotiationValue",
-                DisplayFormat = "Verhand.-Sum.: {0:c2}"
+                DisplayFormat = "Verhand.-∑ = {0:c2}"
             });
 
             s.HtmlRowPrepared = (sender, e) =>
@@ -774,6 +890,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.Settings.ShowFooter = true;
             s.Settings.ShowGroupPanel = true;
             s.Settings.AutoFilterCondition = AutoFilterCondition.Contains;
+            s.Settings.HorizontalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollableHeight =
                 (html.ViewData["ScrollHeight"] == null || (int)html.ViewData["ScrollHeight"] == -1)
@@ -786,7 +903,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.SettingsBehavior.EnableCustomizationWindow = true;
             s.SettingsBehavior.AllowHeaderFilter = true;
             s.SettingsPager.AlwaysShowPager = true;
-            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.NextColumn;
+            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.Control;
             s.SettingsCookies.Enabled = true;
             s.SettingsCookies.CookiesID = "mailNotificationGridStateCookie";
 
@@ -878,8 +995,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             {
                 column.Caption = "Mitarbeiter";
                 column.FieldName = "UserDescriptions";
-                column.MinWidth = 150;
-                column.Width = new Unit(15, UnitType.Percentage);
+                column.MinWidth = 200;
+                column.Width = new Unit(20, UnitType.Percentage);
                 column.SetDataItemTemplateContent(c =>
                 {
                     var userDescriptions = DataBinder.Eval(c.DataItem, "UserDescriptions") as List<string>;
@@ -947,6 +1064,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.Settings.ShowFooter = true;
             s.Settings.ShowGroupPanel = true;
             s.Settings.AutoFilterCondition = AutoFilterCondition.Contains;
+            s.Settings.HorizontalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollBarMode = ScrollBarMode.Auto;
             s.Settings.VerticalScrollableHeight =
                 (html.ViewData["ScrollHeight"] == null || (int)html.ViewData["ScrollHeight"] == -1)
@@ -959,7 +1077,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Extensions
             s.SettingsBehavior.EnableCustomizationWindow = true;
             s.SettingsBehavior.AllowHeaderFilter = true;
             s.SettingsPager.AlwaysShowPager = true;
-            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.NextColumn;
+            s.SettingsResizing.ColumnResizeMode = ColumnResizeMode.Control;
             s.SettingsCookies.Enabled = true;
             s.SettingsCookies.CookiesID = "logGridStateCookie";
 

+ 4 - 0
GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj

@@ -323,6 +323,8 @@
     <Content Include="Views\Misc\Logs.cshtml" />
     <Content Include="Views\Misc\_LogGridPartial.cshtml" />
     <Content Include="Views\Misc\_LogViewPartial.cshtml" />
+    <Content Include="Views\Shared\_EditCommentPartial.cshtml" />
+    <Content Include="Views\Admin\Plugins\_PluginsGridPartial.cshtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -340,6 +342,8 @@
     <Compile Include="App_Start\WebApiConfig.cs" />
     <Compile Include="Controllers\MiscController.cs" />
     <Compile Include="Extensions\ControlHelper.cs" />
+    <Compile Include="Models\Admin\Plugins\PluginDataModel.cs" />
+    <Compile Include="Models\Global\EditEntityCommentModel.cs" />
     <Compile Include="Models\Misc\LogDataModel.cs" />
     <Compile Include="Models\Misc\MailNotificationDataModel.cs" />
     <Compile Include="Implementations\DeviationNotificationPlugin.cs" />

+ 37 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/Plugins/PluginDataModel.cs

@@ -0,0 +1,37 @@
+using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Plugins;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.Plugins
+{
+    public class PluginDataModel
+    {
+        public bool IsInstalled { get; set; }
+        public string SystemName { get; set; }
+        public string FriendlyName { get; set; }
+        public string LogoUrl { get; set; }
+        public string Group { get; set; }
+        public string Author { get; set; }
+        public string Version { get; set; }
+
+        public static PluginDataModel FromPluginDesciptor(PluginDescriptor descriptor, IWebHelper webHelper)
+        {
+            if (descriptor == null)
+                throw new ArgumentNullException("descriptor", "Cannot create PluginDataModel from NULL plugin descriptor.");
+
+            return new PluginDataModel
+            {
+                IsInstalled = descriptor.Installed,
+                SystemName = descriptor.SystemName,
+                FriendlyName = descriptor.FriendlyName,
+                LogoUrl = descriptor.GetLogoUrl(webHelper),
+                Group = descriptor.Group,
+                Author = descriptor.Author,
+                Version = descriptor.Version
+            };
+        }
+    }
+}

+ 14 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/EditEntityCommentModel.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Global
+{
+    public class EditEntityCommentModel
+    {
+        public int EntityId { get; set; }
+        public string EntityType { get; set; }
+        public string Comment { get; set; }
+    }
+}

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/Description.txt → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Description.txt

@@ -1,4 +1,4 @@
-Group: Misc
+Group: Allgemein
 FriendlyName: Nachtragsmanagement Test
 SystemName: GreenTree.Nachtragsmanagement.Test
 Version: 1.0

BIN=BIN
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll


+ 15 - 19
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll.config → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/GreenTree.Nachtragsmanagement.Plugin.Test.dll.config

@@ -23,45 +23,41 @@
     </pages>
   </system.web.webPages.razor>
   <appSettings>
-    <add key="webpages:Version" value="3.0.0.0"/>
-    <add key="webpages:Enabled" value="false"/>
-    <add key="ClientValidationEnabled" value="true"/>
-    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
+    <add key="webpages:Version" value="3.0.0.0" />
+    <add key="webpages:Enabled" value="false" />
+    <add key="ClientValidationEnabled" value="true" />
+    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
   </appSettings>
   <system.web>
-    <compilation debug="true" targetFramework="4.5.2"/>
-    <httpRuntime targetFramework="4.5.2"/>
+    <compilation debug="true" targetFramework="4.5.2" />
+    <httpRuntime targetFramework="4.5.2" />
   </system.web>
   <system.webServer>
     <handlers>
-      <remove name="BlockViewHandler"/>
+      <remove name="BlockViewHandler" />
       <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
     </handlers>
   </system.webServer>
   <runtime>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-5.2.0.0" newVersion="5.2.0.0" />
       </dependentAssembly>
     </assemblyBinding>
   </runtime>
   <system.codedom>
     <compilers>
-      <compiler language="c#;cs;csharp" extension=".cs"
-        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
-        warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
-      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
-        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
-        warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
+      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
+      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
     </compilers>
   </system.codedom>
 </configuration>

+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/Views/Home/Index.cshtml → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Views/Home/Index.cshtml


+ 16 - 25
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/Web.config → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/Web.config

@@ -23,50 +23,41 @@
     </pages>
   </system.web.webPages.razor>
   <appSettings>
-    <add key="webpages:Version" value="3.0.0.0"/>
-    <add key="webpages:Enabled" value="false"/>
-    <add key="ClientValidationEnabled" value="true"/>
-    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
+    <add key="webpages:Version" value="3.0.0.0" />
+    <add key="webpages:Enabled" value="false" />
+    <add key="ClientValidationEnabled" value="true" />
+    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
   </appSettings>
   <system.web>
-    <compilation debug="true" targetFramework="4.5.2"/>
-    <httpRuntime targetFramework="4.5.2"/>
-<!--     <compilation>
-      <assemblies>
-        <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
-      </assemblies>
-    </compilation> -->
+    <compilation debug="true" targetFramework="4.5.2" />
+    <httpRuntime targetFramework="4.5.2" />
   </system.web>
   <system.webServer>
     <handlers>
-      <remove name="BlockViewHandler"/>
-      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+      <remove name="BlockViewHandler" />
+      <add name="BlockViewHandler" path="~/Views/*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
     </handlers>
   </system.webServer>
   <runtime>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
-        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-5.2.0.0" newVersion="5.2.0.0" />
       </dependentAssembly>
     </assemblyBinding>
   </runtime>
   <system.codedom>
     <compilers>
-      <compiler language="c#;cs;csharp" extension=".cs"
-        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
-        warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
-      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
-        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
-        warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
+      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
+      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
     </compilers>
   </system.codedom>
 </configuration>

+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Plugins/Misc.Test/logo.jpg → GreenTree.Nachtragsmanagement.Web/Plugins/Allgemein.Test/logo.jpg


+ 103 - 2
GreenTree.Nachtragsmanagement.Web/Views/Admin/Plugins/View.cshtml

@@ -1,3 +1,104 @@
-@{
+@using GreenTree.Nachtragsmanagement.Web.Models.Global;
+
+@{
     Layout = "~/Views/Shared/_FunctionLayout.cshtml";
-}
+}
+
+@model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Admin.Plugins.PluginDataModel>
+
+<script>
+	var gridScrollHeight;
+	var gridScrollOffset = 130;
+	var resizeFinished;
+
+	$(document).ready(function () {
+		gridScrollHeight = calculateGridScrollHeight();
+		setTimeout(function () {
+			devGridViewPlugin.PerformCallback();
+		}, 500);
+	});
+
+	$(window).resize(function () {
+		clearTimeout(window.resizedFinished);
+		window.resizedFinished = setTimeout(function () {
+			setGridScrollHeight();
+		}, 250);
+	});
+
+	function calculateGridScrollHeight() {
+		var windowHeight = $(window).height();
+		var gridHeaderHeight = $("#devGridViewPlugin_DXHeadersRow0").height();
+		var gridFooterHeight = $("#devGridViewPlugin_DXFooterRow").height();
+		return windowHeight - gridHeaderHeight - gridFooterHeight - gridScrollOffset;
+	}
+
+	function setGridScrollHeight() {
+		gridScrollHeight = calculateGridScrollHeight();
+		devGridViewPlugin.PerformCallback();
+	}
+
+	function toggleInstallation(pluginSystemName, installationType) {
+		if (!pluginSystemName || !installationType) return;
+		if (installationType == "install") {
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("InstallPlugin", "Admin")',
+				data: { pluginName: pluginSystemName },
+				success: function (response) {
+					if (response == "success") {
+						devLoadingPanelRestart.Show();
+						$.ajax({
+							type: "GET",
+							url: '@Url.Action("GetUser", "Admin")',
+							data: { Id: -1 },
+							success: function (response) {
+								devLoadingPanelRestart.Hide();
+								devGridViewPlugin.PerformCallback();
+							}
+						});
+					} else {
+						$("body").append(reponse);
+					}
+				},
+				error: function () {
+					alert("error occured");
+				}
+			});
+		} else if (installationType == "uninstall") {
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("UninstallPlugin", "Admin")',
+				data: { pluginName: pluginSystemName },
+				success: function (response) {
+					if (response == "success") {
+						devLoadingPanelRestart.Show();
+						$.ajax({
+							type: "GET",
+							url: '@Url.Action("GetUser", "Admin")',
+							data: { Id: -1 },
+							success: function (response) {
+								devLoadingPanelRestart.Hide();
+								devGridViewPlugin.PerformCallback();
+							}
+						});
+					} else {
+						$("body").append(reponse);
+					}
+				},
+				error: function () {
+					alert("error occured");
+				}
+			});
+		}
+	}
+</script>
+
+@Html.DevExpress().LoadingPanel(t =>
+{
+	t.Name = "devLoadingPanelRestart";
+	t.Text = "Anwendung wird neugestartet... bitte warten!";
+	t.Modal = true;
+	t.Styles.LoadingDiv.Opacity = 0;
+}).GetHtml()
+
+@Html.Partial("~/Views/Admin/Plugins/_PluginsGridPartial.cshtml", Model)

+ 107 - 0
GreenTree.Nachtragsmanagement.Web/Views/Admin/Plugins/_PluginsGridPartial.cshtml

@@ -0,0 +1,107 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Admin.Plugins.PluginDataModel>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().GridView(s =>
+{
+	s.Name = "devGridViewPlugin";
+	s.KeyFieldName = "Id";
+	s.CallbackRouteValues = new { Controller = "Admin", Action = "PartialPlugins" };
+	s.Width = Unit.Percentage(99);
+	s.Settings.ShowFilterRow = true;
+	s.Settings.ShowFilterRowMenu = true;
+	s.Settings.VerticalScrollBarMode = ScrollBarMode.Auto;
+	s.Settings.VerticalScrollableHeight =
+		(ViewData["ScrollHeight"] == null || (int)ViewData["ScrollHeight"] == -1)
+			? 400
+			: (int)ViewData["ScrollHeight"];
+	s.SettingsPager.AlwaysShowPager = true;
+
+	if (userContext.CurrentUser.HasFunction("Administration-Plugins-Edit"))
+	{
+		s.Columns.Add(column =>
+		{
+			column.Caption = "#";
+			column.SetDataItemTemplateContent(c =>
+			{
+				var isInstalled = Convert.ToBoolean(DataBinder.Eval(c.DataItem, "IsInstalled"));
+				var systemName = DataBinder.Eval(c.DataItem, "SystemName").ToString();
+
+				if (isInstalled)
+					ViewContext.Writer.Write(
+						"<a href=\"#\" onclick=\'toggleInstallation(\"" + systemName + "\",\"uninstall\")'>Deinstallieren</a>");
+				else
+					ViewContext.Writer.Write(
+						"<a href=\"#\" onclick=\'toggleInstallation(\"" + systemName + "\",\"install\")'>Installieren</a>");
+			});
+			column.Settings.AllowDragDrop = DefaultBoolean.False;
+			column.Settings.AllowSort = DefaultBoolean.False;
+			column.Width = 60;
+		});
+	}
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Logo";
+		column.FieldName = "LogoUrl";
+		column.SetDataItemTemplateContent(c =>
+		{
+			var logoPath = DataBinder.Eval(c.DataItem, "LogoUrl").ToString();
+
+			ViewContext.Writer.Write("<img src=\"" + Url.Content(logoPath) + "\" />");
+		});
+		column.MinWidth = 80;
+		column.Width = new Unit(80, UnitType.Pixel);
+		column.CellStyle.HorizontalAlign = HorizontalAlign.Center;
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Gruppe";
+		column.FieldName = "Group";
+		column.MinWidth = 110;
+		column.Width = new Unit(130, UnitType.Pixel);
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Name";
+		column.FieldName = "FriendlyName";
+		column.MinWidth = 120;
+		column.Width = new Unit(150, UnitType.Pixel);
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Systemname";
+		column.FieldName = "SystemName";
+		column.MinWidth = 150;
+		column.Width = new Unit(180, UnitType.Pixel);
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Version";
+		column.FieldName = "Version";
+		column.MinWidth = 70;
+		column.Width = new Unit(90, UnitType.Pixel);
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Autor";
+		column.FieldName = "Author";
+		column.MinWidth = 110;
+		column.Width = new Unit(150, UnitType.Pixel);
+	});
+
+	s.ClientLayout = (sender, e) =>
+	{
+		if (e.LayoutMode == ClientLayoutMode.Loading)
+		{
+			if (Session["UserGridState"] != null)
+				e.LayoutData = (string)Session["UserGridState"];
+		}
+		else
+			Session["UserGridState"] = e.LayoutData;
+	};
+	s.ClientSideEvents.BeginCallback = "function (s, e) { e.customArgs['scrollHeight'] = [ gridScrollHeight ]; }";
+
+	s.Styles.AlternatingRow.BackColor = System.Drawing.Color.FromArgb(247, 247, 247);
+}).Bind(Model).GetHtml()

+ 82 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/_EditCommentPartial.cshtml

@@ -0,0 +1,82 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Global.EditEntityCommentModel
+
+<div class="editCommentContainer">
+
+	<script>
+
+		function saveComment() {
+			var form = $("#commentEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditEntityComment", "Global")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".editCommentContainer").remove();
+							if (response == "success") {
+								if (typeof editCommentCallback === 'function') {
+									editCommentCallback();
+								}
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+
+	</script>
+
+	@Html.DevExpress().PopupControl(p =>
+	{
+		p.Name = "devPopupControlEditComment";
+		p.HeaderText = "Kommentar bearbeiten";
+		p.ShowHeader = true;
+		p.ShowFooter = false;
+		p.Modal = true;
+		p.Width = new Unit(500, UnitType.Pixel);
+		p.MinHeight = new Unit(200, UnitType.Pixel);
+		p.ShowOnPageLoad = true;
+		p.SetContent(() =>
+		{
+			using (Html.BeginForm("EditEntityComment", "Global", FormMethod.Post, new { id = "commentEditForm" }))
+			{
+				ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+				ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.EntityId + "\" id=\"EntityId\" name=\"EntityId\" />");
+				ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.EntityType + "\" id=\"EntityType\" name=\"EntityType\" />");
+
+				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Comment, "Kommentar:"));
+				ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Comment).ToHtmlString());
+				Html.DevExpress().MemoFor(m => m.Comment, t =>
+				{
+					t.Width = new Unit(100, UnitType.Percentage);
+					t.Height = new Unit(90, UnitType.Pixel);
+				}).Render();
+
+				ViewContext.Writer.Write("</div>");
+
+				Html.RenderPartial(
+					"~/Views/Shared/_PopupButtonPanel.cshtml",
+					new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+					{
+						PopupName = "devPopupControlEditComment",
+						AcceptFunction = "function (s, e) { saveComment(); }"
+					}
+				);
+			}
+		});
+		p.CloseAction = CloseAction.CloseButton;
+		p.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+		p.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+		p.Styles.Content.Paddings.Padding = new Unit(0, UnitType.Pixel);
+		p.Styles.ModalBackground.Opacity = 0;
+	}).GetHtml()
+
+</div>

+ 13 - 5
GreenTree.Nachtragsmanagement.Web/Views/Shared/_FunctionLayout.cshtml

@@ -26,6 +26,8 @@
 	<link rel="stylesheet" type="text/css" href="~/Content/function.css" />
 
 	<script>
+		var editCommentCallback = null;
+
 		function showComment(entityType, id, element) {
 			if (!entityType || !id || !element) return;
 			$.ajax({
@@ -39,11 +41,17 @@
 			});
 		}
 
-		function showError(header, message) {
-			var errorPopup = MVCxClientPopupControl.Cast(devPopupControlErrorBox);
-			$("#errorContent").text(message);
-			errorPopup.SetHeaderText(header);
-			errorPopup.Show(element);
+		function editComment(entityType, id, callback) {
+			if (!entityType || !id) return;
+			editCommentCallback = callback;
+			$.ajax({
+				url: '@Url.Action("EditEntityComment", "Global")',
+				data: { entityType: entityType, id: id },
+				success: function (response) {
+					$(".editCommentContainer").remove();
+					$("body").append(response);
+				}
+			});
 		}
 	</script>
 </head>