From a1109438850badc5bd03c5d151623a9df4a4d981 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:03:52 +0100 Subject: [PATCH 01/27] Create ItemController.cs --- .../common/Controllers/ItemController.cs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 generators/spa/templates/common/Controllers/ItemController.cs diff --git a/generators/spa/templates/common/Controllers/ItemController.cs b/generators/spa/templates/common/Controllers/ItemController.cs new file mode 100644 index 00000000..8a38573b --- /dev/null +++ b/generators/spa/templates/common/Controllers/ItemController.cs @@ -0,0 +1,111 @@ +using DotNetNuke.Common; +using DotNetNuke.Common.Utilities; +using DotNetNuke.Security; +using DotNetNuke.UI.Modules; +using DotNetNuke.Web.Api; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Web.Http; +using <%= fullNamespace %>.Components.BaseClasses; +using <%= fullNamespace %>.Data; +using <%= fullNamespace %>.Services.ViewModels; + +namespace <%= fullNamespace %>.Services +{ + [SupportedModules("<%= moduleName %>")] + [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] + + public class ItemController : ApiControllerBase + { + public ItemController() { } + [HttpDelete] + public HttpResponseMessage Delete(int itemId) + { + var item = DbCtx.Items.FirstOrDefault(i => i.ItemId == itemId); + if (item != null) + { + DbCtx.Items.Remove(item); + DbCtx.SaveChanges(); + } + + return Request.CreateResponse(System.Net.HttpStatusCode.NoContent); + } + + [HttpGet] + public HttpResponseMessage Get(int itemId) + { + var itemVm = new ItemViewModel(DbCtx.Items.FirstOrDefault(i => i.ItemId == itemId)); + + return Request.CreateResponse(itemVm); + } + + [HttpGet] + public HttpResponseMessage GetList() + { + List retval = new List(); + List items; + + items = DbCtx.Items.Where(i => i.ModuleId == ActiveModule.ModuleID).ToList(); + items.ForEach(i => retval.Add(new ItemViewModel(i, Globals.IsEditMode()))); + + return Request.CreateResponse(retval); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public HttpResponseMessage Save(ItemViewModel item) + { + if (item.Id > 0) + { + var t = Update(item); + return Request.CreateResponse(System.Net.HttpStatusCode.NoContent); + } + else + { + var t = Create(item); + return Request.CreateResponse(t.ItemId); + } + + } + + private Item Create(ItemViewModel item) + { + Item t = new Item + { + ItemName = item.Name, + ItemDescription = item.Description, + AssignedUserId = item.AssignedUser, + ModuleId = ActiveModule.ModuleID, + CreatedByUserId = UserInfo.UserID, + LastModifiedByUserId = UserInfo.UserID, + CreatedOnDate = DateTime.UtcNow, + LastModifiedOnDate = DateTime.UtcNow + }; + DbCtx.Items.Add(t); + DbCtx.SaveChanges(); + + return t; + } + + private Item Update(ItemViewModel item) + { + + var t = DbCtx.Items.FirstOrDefault(i => i.ItemId == item.Id); + if (t != null) + { + t.ItemName = item.Name; + t.ItemDescription = item.Description; + t.AssignedUserId = item.AssignedUser; + t.LastModifiedByUserId = UserInfo.UserID; + t.LastModifiedOnDate = DateTime.UtcNow; + } + DbCtx.SaveChanges(); + + return t; + } + } +} From 1606b3b64fbc458af0f21849e4e088f59f6dcc0b Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:04:03 +0100 Subject: [PATCH 02/27] Create UserController.cs --- .../common/Controllers/UserController.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 generators/spa/templates/common/Controllers/UserController.cs diff --git a/generators/spa/templates/common/Controllers/UserController.cs b/generators/spa/templates/common/Controllers/UserController.cs new file mode 100644 index 00000000..cab411c8 --- /dev/null +++ b/generators/spa/templates/common/Controllers/UserController.cs @@ -0,0 +1,33 @@ +using <%= fullNamespace %>.Services.ViewModels; +using DotNetNuke.Entities.Users; +using DotNetNuke.Security; +using DotNetNuke.Web.Api; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; + +namespace <%= fullNamespace %>.Services +{ + [SupportedModules("<%= moduleName %>")] + [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] + public class UserController : DnnApiController + { + public UserController() { } + + public HttpResponseMessage Dummy() + { + return Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Dummy called"); + } + public HttpResponseMessage GetList() + { + + var userlist = DotNetNuke.Entities.Users.UserController.GetUsers(this.PortalSettings.PortalId); + var users = userlist.Cast().ToList() + .Select(user => new UserViewModel(user)) + .ToList(); + + return Request.CreateResponse(users); + } + } +} From 3b6367a76915a139485e0563b9d47a323267f727 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:11:47 +0100 Subject: [PATCH 03/27] Create SettingsController.cs --- generators/spa/templates/common/Controllers/SettingsController.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 generators/spa/templates/common/Controllers/SettingsController.cs diff --git a/generators/spa/templates/common/Controllers/SettingsController.cs b/generators/spa/templates/common/Controllers/SettingsController.cs new file mode 100644 index 00000000..e69de29b From 117d17fae9cf6e957934825ddfe7e293fc61a0f1 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:11:52 +0100 Subject: [PATCH 04/27] Create Item.cs --- generators/spa/templates/common/Data/Item.cs | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 generators/spa/templates/common/Data/Item.cs diff --git a/generators/spa/templates/common/Data/Item.cs b/generators/spa/templates/common/Data/Item.cs new file mode 100644 index 00000000..7cd44b3c --- /dev/null +++ b/generators/spa/templates/common/Data/Item.cs @@ -0,0 +1,33 @@ +namespace <%= fullNamespace %>.Data +{ + using System; + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + using System.ComponentModel.DataAnnotations.Schema; + using System.Data.Entity.Spatial; + + public partial class Item + { + [Key] + public int ItemId { get; set; } + + [Required] + public string ItemName { get; set; } + + [Required] + public string ItemDescription { get; set; } + + public int? AssignedUserId { get; set; } + + public int ModuleId { get; set; } + + public DateTime CreatedOnDate { get; set; } + + public int CreatedByUserId { get; set; } + + public DateTime LastModifiedOnDate { get; set; } + + public int LastModifiedByUserId { get; set; } + + } +} \ No newline at end of file From f945a3c7f91831ef14a919b2011af07cba19d4a6 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:11:58 +0100 Subject: [PATCH 05/27] Create ItemViewModel.cs --- .../common/ViewModels/ItemViewModel.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 generators/spa/templates/common/ViewModels/ItemViewModel.cs diff --git a/generators/spa/templates/common/ViewModels/ItemViewModel.cs b/generators/spa/templates/common/ViewModels/ItemViewModel.cs new file mode 100644 index 00000000..8e1404cd --- /dev/null +++ b/generators/spa/templates/common/ViewModels/ItemViewModel.cs @@ -0,0 +1,41 @@ +using <%= fullNamespace %>.Components; +using <%= fullNamespace %>.Data; +using Newtonsoft.Json; + +namespace <%= fullNamespace %>.Services.ViewModels +{ + [JsonObject(MemberSerialization.OptIn)] + public class ItemViewModel + { + public ItemViewModel(Item t) + { + Id = t.ItemId; + Name = t.ItemName; + Description = t.ItemDescription; + AssignedUser = t.AssignedUserId; + } + + public ItemViewModel(Item t, bool canEdit) : this(t) + { + CanEdit = canEdit; + } + + + public ItemViewModel() { } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("assignedUser")] + public int? AssignedUser { get; set; } + + [JsonProperty("canEdit")] + public bool CanEdit { get; } + } +} \ No newline at end of file From 47ddcc7ca5cb12214a1a06826fbd63d8958ed11e Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:12:02 +0100 Subject: [PATCH 06/27] Create UserViewModel.cs --- .../common/ViewModels/UserViewModel.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 generators/spa/templates/common/ViewModels/UserViewModel.cs diff --git a/generators/spa/templates/common/ViewModels/UserViewModel.cs b/generators/spa/templates/common/ViewModels/UserViewModel.cs new file mode 100644 index 00000000..5b320011 --- /dev/null +++ b/generators/spa/templates/common/ViewModels/UserViewModel.cs @@ -0,0 +1,27 @@ +using DotNetNuke.Entities.Users; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace <%= fullNamespace %>.Services.ViewModels +{ + [JsonObject(MemberSerialization.OptIn)] + public class UserViewModel + { + public UserViewModel(UserInfo t) + { + Id = t.UserID; + Name = t.DisplayName; + } + + public UserViewModel() { } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + } +} \ No newline at end of file From b666e8d37a831b65c42d42eb445fa7d167df2be8 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:15:20 +0100 Subject: [PATCH 07/27] Create ModuleContext.cs --- .../templates/common/Data/ModuleContext.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 generators/spa/templates/common/Data/ModuleContext.cs diff --git a/generators/spa/templates/common/Data/ModuleContext.cs b/generators/spa/templates/common/Data/ModuleContext.cs new file mode 100644 index 00000000..b16fe731 --- /dev/null +++ b/generators/spa/templates/common/Data/ModuleContext.cs @@ -0,0 +1,36 @@ +using System; +using System.Data.Entity; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using DotNetNuke.Data; +using DotNetNuke.Framework.Providers; + +namespace <%= fullNamespace %>.Data +{ + public class <%= moduleName %>Context: DbContext + { + public <%= moduleName %>Context() + : base("name=SiteSqlServer") + { + } + + public virtual DbSet Items { get; set; } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + string moduleQualifier = "<%= moduleName %>_"; + // get the dnn data provider configuration + ProviderConfiguration pc = ProviderConfiguration.GetProviderConfiguration("data"); + // Read the configuration specific information for this provider + Provider provider = (Provider)pc.Providers[pc.DefaultProvider]; + // get the objectQualifier + String objectQualifier = provider.Attributes["objectQualifier"]; + // append an underscore when it's not there + if (!string.IsNullOrEmpty(objectQualifier) && !objectQualifier.EndsWith("_")) + objectQualifier += "_"; + + // map the object to the right table + modelBuilder.Entity().ToTable($"{objectQualifier}{moduleQualifier}Items"); + } + } +} From bd75fa7a47d1a6d59f11e25ea2464651d9e0bc8c Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 31 Jan 2023 18:17:06 +0100 Subject: [PATCH 08/27] Update index.js --- generators/spa/index.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/generators/spa/index.js b/generators/spa/index.js index 4a325bde..619dfa65 100644 --- a/generators/spa/index.js +++ b/generators/spa/index.js @@ -258,7 +258,7 @@ module.exports = class extends DnnGeneratorBase { 'html-webpack-plugin': '^3.2.0', // eslint-disable-next-line prettier/prettier 'marked': '^0.5.2', - 'node-sass': '^4.11.0', + 'node-sass': '^8.0.0', 'sass-loader': '^7.1.0', 'style-loader': '^0.23.1', // eslint-disable-next-line prettier/prettier @@ -268,10 +268,13 @@ module.exports = class extends DnnGeneratorBase { 'webpack-node-externals': '^1.7.2' }, dependencies: { - 'prop-types': '^15.6.2', - // eslint-disable-next-line prettier/prettier - 'react': '^16.6.3', - 'react-dom': '^16.6.3' + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "web-vitals": "^2.1.4" } }; From 9ffac6b365335d9a0f861deaf960ee1b4276a5a5 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Wed, 1 Feb 2023 01:07:52 +0100 Subject: [PATCH 09/27] create common files for the SPA template --- generators/spa/index.js | 19 ++++- .../spa/templates/ReactJS/common/Module.build | 53 ++++++++++++ .../common/Controllers/ItemController.cs | 4 +- .../common/Controllers/SettingsController.cs | 84 +++++++++++++++++++ .../common/Controllers/UserController.cs | 2 +- .../SqlDataProvider/00.00.01.SqlDataProvider | 42 ++++++++++ .../SqlDataProvider/Uninstall.SqlDataProvider | 3 + .../spa/templates/common/RouteConfig.cs | 21 +++-- .../common/ViewModels/ItemViewModel.cs | 2 +- .../common/ViewModels/SettingsViewModel.cs | 47 +++++++++++ .../common/ViewModels/UserViewModel.cs | 2 +- generators/spa/templates/common/manifest.dnn | 13 ++- 12 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 generators/spa/templates/ReactJS/common/Module.build create mode 100644 generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/00.00.01.SqlDataProvider create mode 100644 generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/Uninstall.SqlDataProvider create mode 100644 generators/spa/templates/common/ViewModels/SettingsViewModel.cs diff --git a/generators/spa/index.js b/generators/spa/index.js index 619dfa65..ac48333a 100644 --- a/generators/spa/index.js +++ b/generators/spa/index.js @@ -181,6 +181,24 @@ module.exports = class extends DnnGeneratorBase { template ); + this.fs.copyTpl( + this.templatePath('common/Data/**'), + this.destinationPath(moduleName + '/Data/'), + template + ); + + this.fs.copyTpl( + this.templatePath('common/ViewModels/**'), + this.destinationPath(moduleName + '/ViewModels/'), + template + ); + + this.fs.copyTpl( + this.templatePath('common/Providers/**'), + this.destinationPath(moduleName + '/Providers/'), + template + ); + // Do all templated copies this.fs.copyTpl( this.templatePath('../../common/src/**'), @@ -293,7 +311,6 @@ module.exports = class extends DnnGeneratorBase { 'eslint': '^5.8.0', 'eslint-loader': '^2.1.1', 'eslint-plugin-react': '^7.11.1', - 'react-hot-loader': '^4.3.12' }; } else { this._writeTsConfig(); diff --git a/generators/spa/templates/ReactJS/common/Module.build b/generators/spa/templates/ReactJS/common/Module.build new file mode 100644 index 00000000..62283058 --- /dev/null +++ b/generators/spa/templates/ReactJS/common/Module.build @@ -0,0 +1,53 @@ + + + <%= moduleName %> + <%= moduleName %> + <%= fullNamespace %> + zip + $(MSBuildProjectDirectory)\..\..\Build + $(MSBuildProjectDirectory)\..\..\Website + $(WebsitePath)\Install\Module + $(WebsitePath)\DesktopModules\$(ModulePath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generators/spa/templates/common/Controllers/ItemController.cs b/generators/spa/templates/common/Controllers/ItemController.cs index 8a38573b..564f56fe 100644 --- a/generators/spa/templates/common/Controllers/ItemController.cs +++ b/generators/spa/templates/common/Controllers/ItemController.cs @@ -12,9 +12,9 @@ using System.Web.Http; using <%= fullNamespace %>.Components.BaseClasses; using <%= fullNamespace %>.Data; -using <%= fullNamespace %>.Services.ViewModels; +using <%= fullNamespace %>.ViewModels; -namespace <%= fullNamespace %>.Services +namespace <%= fullNamespace %>.Controllers { [SupportedModules("<%= moduleName %>")] [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] diff --git a/generators/spa/templates/common/Controllers/SettingsController.cs b/generators/spa/templates/common/Controllers/SettingsController.cs index e69de29b..b83e92cc 100644 --- a/generators/spa/templates/common/Controllers/SettingsController.cs +++ b/generators/spa/templates/common/Controllers/SettingsController.cs @@ -0,0 +1,84 @@ +/* +Copyright Upendo Ventures, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +using System.Net.Http; +using System.Net; +using System.Web.Http; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Web.Api; +using DotNetNuke.Security; +using Telerik.Web.UI.Calendar.Utils; +using <%= fullNamespace %>; +using <%= fullNamespace %>.ViewModels; + +namespace <%= fullNamespace %>.Controllers +{ + [SupportedModules("<%= moduleName %>")] + [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] + public class SettingsController : DnnApiController + { + public SettingsController() { } + + [HttpGet] //[baseURL]/settings/load + + public HttpResponseMessage LoadSettings() + { + var settings = new SettingsViewModel(); + + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_Name)) + { + settings.Name = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_Name].ToString(); + } + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_Description)) + { + settings.Description = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_Description].ToString(); + } + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_CreatedByUserId)) + { + settings.CreatedByUserId = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_CreatedByUserId].ToString(); + } + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_AssignedUserId)) + { + settings.AssignedUserId = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_AssignedUserId].ToString(); + } + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_ItemId)) + { + settings.ItemId = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_ItemId].ToString(); + } + if (ActiveModule.ModuleSettings.ContainsKey(QuickSettings.MODSETTING_CreatedOnDate)) + { + settings.CreatedOnDate = ActiveModule.ModuleSettings[QuickSettings.MODSETTING_CreatedOnDate].ToString(); + } + + return Request.CreateResponse(HttpStatusCode.OK, settings); + } + + [HttpPost] //[baseURL]/settings/save + [ActionName("save")] + [ValidateAntiForgeryToken] + public HttpResponseMessage SaveSettings(SettingsViewModel settings) + { + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_Name, settings.Name); + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_Description, settings.Description); + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_CreatedByUserId, settings.CreatedByUserId); + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_AssignedUserId, settings.AssignedUserId); + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_ItemId, settings.ItemId); + ModuleController.Instance.UpdateModuleSetting(ActiveModule.ModuleID, QuickSettings.MODSETTING_CreatedOnDate, settings.CreatedOnDate); + + return Request.CreateResponse(HttpStatusCode.OK, "Success"); + } + } + +} diff --git a/generators/spa/templates/common/Controllers/UserController.cs b/generators/spa/templates/common/Controllers/UserController.cs index cab411c8..536dc47d 100644 --- a/generators/spa/templates/common/Controllers/UserController.cs +++ b/generators/spa/templates/common/Controllers/UserController.cs @@ -7,7 +7,7 @@ using System.Net; using System.Net.Http; -namespace <%= fullNamespace %>.Services +namespace <%= fullNamespace %>.Controllers { [SupportedModules("<%= moduleName %>")] [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] diff --git a/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/00.00.01.SqlDataProvider b/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/00.00.01.SqlDataProvider new file mode 100644 index 00000000..8511abb4 --- /dev/null +++ b/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/00.00.01.SqlDataProvider @@ -0,0 +1,42 @@ +/************************************************************/ +/***** SqlDataProvider *****/ +/***** *****/ +/***** *****/ +/***** Note: To manually execute this script you must *****/ +/***** perform a search and replace operation *****/ +/***** for {databaseOwner} and {objectQualifier} *****/ +/***** *****/ +/************************************************************/ + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<%= moduleName %>_Items]') AND type in (N'U')) +DROP TABLE {databaseOwner}[{objectQualifier}<%= moduleName %>_Items] +GO + +CREATE TABLE {databaseOwner}{objectQualifier}<%= moduleName %>_Items + ( + ItemId int NOT NULL IDENTITY (1, 1), + ItemName nvarchar(MAX) NOT NULL, + ItemDescription nvarchar(MAX) NOT NULL, + AssignedUserId int NULL, + ModuleId int NOT NULL, + CreatedOnDate datetime NOT NULL, + CreatedByUserId int NOT NULL, + LastModifiedOnDate datetime NOT NULL, + LastModifiedByUserId int NOT NULL + ) ON [PRIMARY] + TEXTIMAGE_ON [PRIMARY] +GO + + +ALTER TABLE {databaseOwner}{objectQualifier}<%= moduleName %>_Items ADD CONSTRAINT + PK_{objectQualifier}<%= moduleName %>_Items PRIMARY KEY CLUSTERED + ( + ItemId + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] + +GO + + +/************************************************************/ +/***** SqlDataProvider *****/ +/************************************************************/ diff --git a/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/Uninstall.SqlDataProvider b/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/Uninstall.SqlDataProvider new file mode 100644 index 00000000..712e6962 --- /dev/null +++ b/generators/spa/templates/common/Providers/DataProviders/SqlDataProvider/Uninstall.SqlDataProvider @@ -0,0 +1,3 @@ +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}<%= moduleName %>_Items]') AND type in (N'U')) +DROP TABLE {databaseOwner}[{objectQualifier}<%= moduleName %>_Items] +GO diff --git a/generators/spa/templates/common/RouteConfig.cs b/generators/spa/templates/common/RouteConfig.cs index 6e16a68d..25a3bc21 100644 --- a/generators/spa/templates/common/RouteConfig.cs +++ b/generators/spa/templates/common/RouteConfig.cs @@ -7,15 +7,26 @@ ' */ using DotNetNuke.Web.Api; +using System.Web.Http; -namespace <%= namespace%>.Modules.<%= moduleName %> +namespace <%= fullNamespace %> { - public class RouteConfig : IServiceRouteMapper + /// + /// The ServiceRouteMapper tells the DNN Web API Framework what routes this module uses + /// + public class ServiceRouteMapper : IServiceRouteMapper { + /// + /// RegisterRoutes is used to register the module's routes + /// + /// public void RegisterRoutes(IMapRoute mapRouteManager) { - mapRouteManager.MapHttpRoute("<%= namespace%>.Modules.<%= moduleName %>", "<%= namespace%>.Modules.<%= moduleName %>", "{controller}/{action}", new[] - {"<%= namespace%>.Modules.<%= moduleName %>.Controllers"}); + mapRouteManager.MapHttpRoute( + moduleFolderName: "<%= moduleName %>", + routeName: "default", + url: "{controller}/{action}", + namespaces: new[] { "<%= fullNamespace %>.Controllers" }); } } -} +} \ No newline at end of file diff --git a/generators/spa/templates/common/ViewModels/ItemViewModel.cs b/generators/spa/templates/common/ViewModels/ItemViewModel.cs index 8e1404cd..48741d0d 100644 --- a/generators/spa/templates/common/ViewModels/ItemViewModel.cs +++ b/generators/spa/templates/common/ViewModels/ItemViewModel.cs @@ -2,7 +2,7 @@ using <%= fullNamespace %>.Data; using Newtonsoft.Json; -namespace <%= fullNamespace %>.Services.ViewModels +namespace <%= fullNamespace %>.ViewModels { [JsonObject(MemberSerialization.OptIn)] public class ItemViewModel diff --git a/generators/spa/templates/common/ViewModels/SettingsViewModel.cs b/generators/spa/templates/common/ViewModels/SettingsViewModel.cs new file mode 100644 index 00000000..988de0e5 --- /dev/null +++ b/generators/spa/templates/common/ViewModels/SettingsViewModel.cs @@ -0,0 +1,47 @@ +/* +Copyright Upendo Ventures, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +using System; +using Newtonsoft.Json; + +namespace <%= fullNamespace %>.ViewModels +{ + [Serializable] + [JsonObject(MemberSerialization.OptIn)] + public class SettingsViewModel + { + public SettingsViewModel() + { + } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("itemId")] + public string ItemId { get; set; } + + [JsonProperty("assignedUserId")] + public string AssignedUserId { get; set; } + + [JsonProperty("createdByUserId")] + public string CreatedByUserId { get; set; } + + [JsonProperty("createdOnDate")] + public string CreatedOnDate { get; set; } + } +} diff --git a/generators/spa/templates/common/ViewModels/UserViewModel.cs b/generators/spa/templates/common/ViewModels/UserViewModel.cs index 5b320011..b467f743 100644 --- a/generators/spa/templates/common/ViewModels/UserViewModel.cs +++ b/generators/spa/templates/common/ViewModels/UserViewModel.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Web; -namespace <%= fullNamespace %>.Services.ViewModels +namespace <%= fullNamespace %>.ViewModels { [JsonObject(MemberSerialization.OptIn)] public class UserViewModel diff --git a/generators/spa/templates/common/manifest.dnn b/generators/spa/templates/common/manifest.dnn index 7292f1d7..4a059074 100644 --- a/generators/spa/templates/common/manifest.dnn +++ b/generators/spa/templates/common/manifest.dnn @@ -94,12 +94,19 @@ - + + <%= fullNamespace %>.dll + bin + + + EntityFramework.dll + bin + + + EntityFramework.SqlServer.dll bin - <%= namespace %>.<%= moduleName %>.dll - <%= version %> From aab4589b637a5b072cdada5f4508ba9d405508ce Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:54:52 +0100 Subject: [PATCH 10/27] Implement the Items component --- .../ReactJS/jsx/src/components/Items.jsx | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 generators/spa/templates/ReactJS/jsx/src/components/Items.jsx diff --git a/generators/spa/templates/ReactJS/jsx/src/components/Items.jsx b/generators/spa/templates/ReactJS/jsx/src/components/Items.jsx new file mode 100644 index 00000000..534edd4b --- /dev/null +++ b/generators/spa/templates/ReactJS/jsx/src/components/Items.jsx @@ -0,0 +1,221 @@ +import React from "react"; +import { useState, useEffect } from "react"; +const moduleId = window.getmoduleId(); +const serviceFramework = window.$.ServicesFramework(moduleId); +const token = serviceFramework.getAntiForgeryValue(); +const tabId = serviceFramework.getTabId(); +const baseUrl ="DesktopModules/<%= moduleName %>/API/"; + +const Items = () => { + const [modal, setModal] = useState(false); + const [items, setItems] = useState(null); + const [users, setUsers] = useState(null); + const [description, setDescription] = useState(null); + const [name, setName] = useState(null); + const [assignedUser, setUser] = useState(null); + const [id, setId] = useState(0); + // SETTINGS + const [idSetting, setIdSetting] = useState(false); + const [nameSetting, setNameSetting] = useState(false); + const [descriptionSetting, setDescriptionSetting] = useState(false); + const [createdOnDateSetting, setCreatedOnDateSetting] = useState(false); + + const loadItems = () => { + const url = baseUrl+"Item/GetList"; + fetch(url, + { + method: "GET", + headers: { + "ModuleId": moduleId, + "RequestVerificationToken": token, + "TabId": tabId + } + }).then(res => { + return res.json(); + }).then(data => { + setItems(data); + }); + }; + + const loadSettings = () => { + const url = baseUrl+"Settings/LoadSettings"; + fetch(url, + { + method: "GET", + headers: { + "ModuleId": moduleId, + "RequestVerificationToken": token, + "TabId": tabId + } + }).then(res => { + return res.json(); + }).then(data => { + setIdSetting(data.itemId === "true" ? true : false); + setNameSetting(data.name === "true" ? true : false); + setDescriptionSetting(data.description === "true" ? true : false); + setCreatedOnDateSetting(data.createdOnDate === "true" ? true : false); + }); + }; + + const cancelAdd = () => { + setModal(false); + resetItem(); + }; + + const resetItem = () => { + setName(null); + setId(0); + setDescription(null); + setUser(null); + }; + + const editItem = (item) => { + setName(item.name); + setUser(item.assignedUser); + setDescription(item.description); + setId(item.id); + setModal(true); + }; + + const saveChanges = () => { + const item = { id, name, description, assignedUser }; + const url = baseUrl + "Item/Save"; + fetch(url, + { + method: "POST", + headers: { + "ModuleId": moduleId, + "RequestVerificationToken": token, + "TabId": tabId, + "Content-Type": "application/json" + }, + body: JSON.stringify(item) + }).then(res => { + if (res.ok) { + resetItem(); + setModal(false); + loadItems(); + } + }); + }; + + const loadUsers = () => { + const url = baseUrl + "User/GetList"; + fetch(url, + { + method: "GET", + headers: { + "ModuleId": moduleId, + "RequestVerificationToken": token, + "TabId": tabId + } + }).then(res => { + return res.json(); + }).then(data => { + setUsers(data); + }); + }; + + useEffect(() => { + loadItems(); + loadSettings(); + loadUsers(); + }, []); + + const removeItem = (itemId) => { + const url = baseUrl + "Item/Delete?itemId=" + itemId; + + if (confirm("Do you want to remove this item?")) { + fetch(url, + { + method: "DELETE", + headers: { + "ModuleId": moduleId, + "RequestVerificationToken": token, + "TabId": tabId + } + }).then(res => { + if (!res.ok) { + throw new Error("HTTP status " + res.status); + } else { + loadItems(); + } + }); + } + }; + + return (
+
+

Item list

+
+ + + + + {idSetting && } + {nameSetting && } + {descriptionSetting && } + + + + + + {items && items.map((item) => ( + {idSetting && } + {nameSetting && } + {descriptionSetting && } + {createdOnDateSetting && } + + ))} + +
IdNameDescriptionCreated on
{item.id}{item.name}{item.description}{item.createdOnDate} + + +
+ {modal && } +
); +}; + +export default Items; From 25b6dde98cb60e393f193d2d8fa3fb49eefbfbba Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:01 +0100 Subject: [PATCH 11/27] Update app.jsx --- generators/spa/templates/ReactJS/jsx/src/app.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/generators/spa/templates/ReactJS/jsx/src/app.jsx b/generators/spa/templates/ReactJS/jsx/src/app.jsx index 6225b5ac..e9fa749d 100644 --- a/generators/spa/templates/ReactJS/jsx/src/app.jsx +++ b/generators/spa/templates/ReactJS/jsx/src/app.jsx @@ -1,12 +1,10 @@ import React from "react"; import * as ReactDOM from "react-dom"; -import Hello from "./components/Hello"; +import Items from "./components/Items"; ReactDOM.render( -
-
- -
-
, + + + , document.getElementById("<%= namespace.toLowerCase() %><%= moduleName %>") ); \ No newline at end of file From d2d466ed2a6fec654dec572026cb638417647d21 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:08 +0100 Subject: [PATCH 12/27] Update ItemViewModel.cs --- generators/spa/templates/common/ViewModels/ItemViewModel.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/generators/spa/templates/common/ViewModels/ItemViewModel.cs b/generators/spa/templates/common/ViewModels/ItemViewModel.cs index 48741d0d..c3e49e61 100644 --- a/generators/spa/templates/common/ViewModels/ItemViewModel.cs +++ b/generators/spa/templates/common/ViewModels/ItemViewModel.cs @@ -13,6 +13,7 @@ public ItemViewModel(Item t) Name = t.ItemName; Description = t.ItemDescription; AssignedUser = t.AssignedUserId; + CreatedOnDate = t.CreatedOnDate.ToShortDateString(); } public ItemViewModel(Item t, bool canEdit) : this(t) @@ -37,5 +38,9 @@ public ItemViewModel() { } [JsonProperty("canEdit")] public bool CanEdit { get; } + + [JsonProperty("createdOnDate")] + public string CreatedOnDate { get; } + } } \ No newline at end of file From e48958f5367a1b0d1cb6d3ac607eb507f08e1a3a Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:23 +0100 Subject: [PATCH 13/27] Update View.html --- generators/spa/templates/common/src/View.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/generators/spa/templates/common/src/View.html b/generators/spa/templates/common/src/View.html index 044e14d6..fc423e2e 100644 --- a/generators/spa/templates/common/src/View.html +++ b/generators/spa/templates/common/src/View.html @@ -2,8 +2,13 @@ securityAccessLevel : "Edit", title: "Edit", titleKey: "EditModule", - localResourceFile: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/App_LocalResources/View.resx" + localResourceFile: "~/DesktopModules/<%= moduleName %>/App_LocalResources/View.resx" }]
-[CSS:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/module.css"}] -[JavaScript:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/scripts/app-bundle.js", provider: "DnnFormBottomProvider"}] + +[CSS:{ path: "~/DesktopModules/<%= moduleName %>/Resources/module.css"}] +[JavaScript:{ path: "~/DesktopModules/<%= moduleName %>/dist/Resources/scripts/app-bundle.js", provider: "DnnFormBottomProvider"}] From e10a09df454fc6a5455ae99b16cc8d8cf9e6a55c Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:29 +0100 Subject: [PATCH 14/27] Update Settings.html --- .../spa/templates/common/src/Settings.html | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/generators/spa/templates/common/src/Settings.html b/generators/spa/templates/common/src/Settings.html index 49bb70be..92233d09 100644 --- a/generators/spa/templates/common/src/Settings.html +++ b/generators/spa/templates/common/src/Settings.html @@ -1,3 +1,27 @@ -
-[CSS:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/module.css"}] -[JavaScript:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/scripts/settings-bundle.js", provider: "DnnFormBottomProvider"}] +[JavaScript:{ jsname: "JQuery" }] +[JavaScript:{ jsname: "Knockout" }] +[JavaScript:{ path: "~/Resources/Shared/scripts/dnn.jquery.js"}] +[JavaScript:{ path: "~/DesktopModules/<%= moduleName %>/dist/Resources/scripts/common.js"}] +[JavaScript:{ path: "~/DesktopModules/<%= moduleName %>/dist/Resources/scripts/QuickSettings.js"}] + +
+ +
+ +
+ +
+ +
+ +
+
+
+ \ No newline at end of file From 578e40459b8c0d50818492cd74422f1acc83f1ed Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:52 +0100 Subject: [PATCH 15/27] Create Module.csproj --- .../templates/ReactJS/common/Module.csproj | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 generators/spa/templates/ReactJS/common/Module.csproj diff --git a/generators/spa/templates/ReactJS/common/Module.csproj b/generators/spa/templates/ReactJS/common/Module.csproj new file mode 100644 index 00000000..bd985563 --- /dev/null +++ b/generators/spa/templates/ReactJS/common/Module.csproj @@ -0,0 +1,165 @@ + + + + Debug + AnyCPU + + + 2.0 + {<%= guid %>} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + <%= fullNamespace %> + <%= fullNamespace %> + v4.8 + false + + + + + + .\ + true + + + 12.0 + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + bin\<%= fullNamespace %>.xml + + + pdbonly + true + bin\ + TRACE + prompt + 4 + bin\<%= fullNamespace %>.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + + Designer + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + web.config + + + web.config + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + True + + + + + + + + From 58c57691b9d61140de32d559e0024a2d3610c4d6 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:55:56 +0100 Subject: [PATCH 16/27] Create ApiControllerBase.cs --- .../BaseClasses/ApiControllerBase.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 generators/spa/templates/common/Components/BaseClasses/ApiControllerBase.cs diff --git a/generators/spa/templates/common/Components/BaseClasses/ApiControllerBase.cs b/generators/spa/templates/common/Components/BaseClasses/ApiControllerBase.cs new file mode 100644 index 00000000..0c544be3 --- /dev/null +++ b/generators/spa/templates/common/Components/BaseClasses/ApiControllerBase.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using DotNetNuke.Web.Api; +using <%= fullNamespace %>.Data; + +namespace <%= fullNamespace %>.Components.BaseClasses +{ + public class ApiControllerBase : DnnApiController + { + private const string DBCONTEXT_KEY = "<%= moduleName %>Context_Instance"; + + public <%= moduleName %>Context DbCtx + { + get + { + return GetContext(); + } + } + + /// + /// Returns a DbContext object for use with this request. Instanciates a new DbContext when requested in the parameter. When using createNewInstance, you should always dispose your DbContext yourself. + /// + /// + /// + protected <%= moduleName %>Context GetContext(bool createNewInstance = false) + { + // if a new instance is requested: return one + if (createNewInstance) return new <%= moduleName %>Context(); + + // get a reference to the HttpContext + var ctx = Request.Properties["MS_HttpContext"] as HttpContextWrapper; + + <%= moduleName %>Context retval = null; + // se if we have one in the HttpContext already + if (ctx.Items[DBCONTEXT_KEY] == null) + { + retval = new <%= moduleName %>Context(); + // store in HttpContext + ctx.Items[DBCONTEXT_KEY] = retval; + } + else + { + // get from HttpContext + retval = (<%= moduleName %>Context)ctx.Items[DBCONTEXT_KEY]; + } + + return retval; + } + + protected override void Dispose(bool disposing) + { + // get a reference to the HttpContext + var ctx = Request.Properties["MS_HttpContext"] as HttpContextWrapper; + + // dispose of stored DbContext + if (ctx.Items[DBCONTEXT_KEY] != null) + { + var dbctx = (<%= moduleName %>Context)ctx.Items[DBCONTEXT_KEY]; + dbctx.Dispose(); + } + + base.Dispose(disposing); + } + } +} From 642eee94511f59469b6cc8c078d63ea14605c6c1 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Mon, 6 Feb 2023 15:56:53 +0100 Subject: [PATCH 17/27] update manifest and user controller --- generators/spa/index.js | 20 ++++++++++++++++++- .../common/Controllers/UserController.cs | 2 +- generators/spa/templates/common/manifest.dnn | 6 +++--- generators/spa/templates/common/src/Edit.html | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/generators/spa/index.js b/generators/spa/index.js index ac48333a..5ba70a3c 100644 --- a/generators/spa/index.js +++ b/generators/spa/index.js @@ -231,8 +231,26 @@ module.exports = class extends DnnGeneratorBase { ); this.fs.copyTpl( - this.templatePath('../../common/csproj/_Project.csproj'), + this.templatePath('common/symbols.dnn'), + this.destinationPath(moduleName + '/' + moduleName + '_Symbols.dnn'), + template + ); + + this.fs.copyTpl( + this.templatePath(spaType + '/common/Module.csproj'), this.destinationPath(moduleName + '/' + moduleName + '.csproj'), + template + ); + + this.fs.copyTpl( + this.templatePath(spaType + '/common/Module.build'), + this.destinationPath(moduleName + '/Module.build'), + template + ); + + this.fs.copyTpl( + this.templatePath('common/Data/ModuleContext.cs'), + this.destinationPath(moduleName + '/Data/' + moduleName + 'Context.cs'), template ); diff --git a/generators/spa/templates/common/Controllers/UserController.cs b/generators/spa/templates/common/Controllers/UserController.cs index 536dc47d..b9ce01c5 100644 --- a/generators/spa/templates/common/Controllers/UserController.cs +++ b/generators/spa/templates/common/Controllers/UserController.cs @@ -1,4 +1,4 @@ -using <%= fullNamespace %>.Services.ViewModels; +using <%= fullNamespace %>.ViewModels; using DotNetNuke.Entities.Users; using DotNetNuke.Security; using DotNetNuke.Web.Api; diff --git a/generators/spa/templates/common/manifest.dnn b/generators/spa/templates/common/manifest.dnn index 4a059074..3ce00da8 100644 --- a/generators/spa/templates/common/manifest.dnn +++ b/generators/spa/templates/common/manifest.dnn @@ -49,7 +49,7 @@ - DesktopModules/<%= moduleName %>/View.html + DesktopModules/<%= moduleName %>/dist/View.html False <%= moduleName %> SPA View @@ -58,7 +58,7 @@ Edit - DesktopModules/<%= moduleName %>/Edit.html + DesktopModules/<%= moduleName %>/dist/Edit.html False Add/Edit Menu Item Edit @@ -69,7 +69,7 @@ QuickSettings - DesktopModules/<%= moduleName %>/Settings.html + DesktopModules/<%= moduleName %>/dist/Settings.html False <%= moduleName %> Settings Edit diff --git a/generators/spa/templates/common/src/Edit.html b/generators/spa/templates/common/src/Edit.html index efcdb29a..663f5bae 100644 --- a/generators/spa/templates/common/src/Edit.html +++ b/generators/spa/templates/common/src/Edit.html @@ -1,3 +1,3 @@ 
[CSS:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/module.css"}] -[JavaScript:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/Resources/scripts/edit-bundle.js", provider: "DnnFormBottomProvider"}] +[JavaScript:{ path: "~/DesktopModules/<%= namespace %>/<%= moduleName %>/dist/Resources/scripts/edit-bundle.js", provider: "DnnFormBottomProvider"}] From a4243a67f07ab665869a747f2d554ba8ee7b51d8 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 02:55:50 +0100 Subject: [PATCH 18/27] adding common files --- .../src/Resources/scripts/QuickSettings.js | 97 +++++++++++ .../common/src/Resources/scripts/common.js | 152 ++++++++++++++++++ .../common/src/Resources/scripts/useFetch.js | 47 ++++++ 3 files changed, 296 insertions(+) create mode 100644 generators/spa/templates/common/src/Resources/scripts/QuickSettings.js create mode 100644 generators/spa/templates/common/src/Resources/scripts/common.js create mode 100644 generators/spa/templates/common/src/Resources/scripts/useFetch.js diff --git a/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js b/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js new file mode 100644 index 00000000..0d55476a --- /dev/null +++ b/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js @@ -0,0 +1,97 @@ +var dnnspamodule = dnnspamodule || {}; + +dnnspamodule.quickSettings = function (root, moduleId) { + console.log(moduleId); + let utils = new common.Utils(); + let alert = new common.Alert(); + let parentSelector = "[id='" + root + "']"; + // Setup your settings service endpoint + let service = { + baseUrl: "DesktopModules/React7/API/", + framework: $.ServicesFramework(moduleId), + controller: "Settings" + }; + + let SaveSettings = function () { + + let name = $("#Name").is(":checked"); + let description = $("#Description").is(":checked"); + let assignedUserId = $("#AssignedUserId").is(":checked"); + let createdOnDate = $("#CreatedOnDate").is(":checked"); + let itemId = $("#ItemId").is(":checked"); + + let deferred = $.Deferred(); + let params = { + name: name, + description: description, + assignedUserId: assignedUserId, + createdOnDate: createdOnDate, + itemId: itemId + }; + + utils.get("POST", "save", service, params, + function (data) { + + deferred.resolve(); + location.reload(); + }, + function (error, exception) { + // fail + let deferred = $.Deferred(); + deferred.reject(); + alert.danger({ + selector: parentSelector, + text: error.responseText, + status: error.status + }); + }, + function () { + }); + + return deferred.promise(); + }; + + let CancelSettings = function () { + let deferred = $.Deferred(); + deferred.resolve(); + return deferred.promise(); + }; + + let LoadSettings = function () { + let params = {}; + + utils.get("GET", "LoadSettings", service, params, + function (data) { + $("#CreatedOnDate").prop("checked", data.createdOnDate == "true"); + $("#Name").prop("checked", data.name == "true"); + $("#Description").prop("checked", data.description == "true"); + $("#ItemId").prop("checked", data.itemId == "true"); + }, + function (error, exception) { + // fail + console.log("12345657897"); + console.log(error); + alert.danger({ + selector: parentSelector, + text: error.responseText, + status: error.status + }); + }, + function () { + }); + }; + + let init = function () { + // Wire up the default save and cancel buttons + $(root).dnnQuickSettings({ + moduleId: moduleId, + onSave: SaveSettings, + onCancel: CancelSettings + }); + LoadSettings(); + }; + + return { + init: init + }; +}; \ No newline at end of file diff --git a/generators/spa/templates/common/src/Resources/scripts/common.js b/generators/spa/templates/common/src/Resources/scripts/common.js new file mode 100644 index 00000000..2d51536d --- /dev/null +++ b/generators/spa/templates/common/src/Resources/scripts/common.js @@ -0,0 +1,152 @@ +var common = common || {}; + +common.Utils = function () { + + let get = function (httpMethod, action, service, params, success, fail, always) { + let jqxhr = $.ajax({ + url: service.baseUrl + service.controller + "/" + action, + beforeSend: service.framework.setModuleHeaders, + type: httpMethod, + async: true, + data: httpMethod == "GET" ? "" : JSON.stringify(params), + dataType: httpMethod == "GET" ? "" : "json", + contentType: httpMethod == "GET" ? "" : "application/json; charset=UTF-8" + }).done(function (data) { + if (typeof (success) === "function") { + success(data); + } + }).fail(function (error, exception) { + if (typeof (fail) === "function") { + fail(error, exception); + } + }).always(function () { + if (typeof (always) === "function") { + always(); + } + }); + }; + + let addRewriteQueryString = function (hash, decode) { + let path = location.pathname; + let queryString = path.substring(path.search("/ctl/") + 1); + let keyValues = queryString.split("/"); + + for (let i = 0; i < keyValues.length; i += 2) { + hash[decode(keyValues[i])] = decode(keyValues[i + 1]); + } + return hash; + }; + + let getQueryStrings = function () { + let assoc = {}; + let decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); }; + let queryString = location.search.substring(1); + let keyValues = queryString.split("&"); + + for (let i = 0; i < keyValues.length; i++) { + let key = keyValues[i].split("="); + if (key.length > 1) { + assoc[decode(key[0])] = decode(key[1]); + } + } + return addRewriteQueryString(assoc, decode); + }; + + let loading = function (icon, cssClass) { + $(icon).toggleClass(cssClass).toggleClass("fa-refresh fa-spin"); + }; + + return { + get: get, + getQueryStrings: getQueryStrings, + addRewriteQueryString: addRewriteQueryString, + loading: loading + }; +}; + + +common.Alert = function () { + + let success = function (message) { + message.redirect = typeof (message.redirect) !== "undefined" ? message.redirect : false; + + $("") + .appendTo($(message.selector)) + .slideDown(800, function () { + if (message.redirect) { + setTimeout(function () { + location.href = typeof (message.postBack) !== "undefined" ? message.postBack : "/"; + }, 3000); + } + }); + }; + + let info = function (message) { + message.redirect = typeof (message.redirect) !== "undefined" ? message.redirect : false; + + $("") + .appendTo($(message.selector)) + .slideDown(800, function () { + if (message.redirect) { + setTimeout(function () { + location.href = typeof (message.postBack) !== "undefined" ? message.postBack : "/"; + }, 3000); + } + }); + }; + + let warning = function (message) { + message.redirect = typeof (message.redirect) !== "undefined" ? message.redirect : false; + + $("") + .appendTo($(message.selector)) + .slideDown(800, function () { + if (message.redirect) { + setTimeout(function () { + location.href = typeof (message.postBack) !== "undefined" ? message.postBack : "/"; + }, 3000); + } + }); + }; + + let danger = function (message) { + message.redirect = typeof (message.redirect) !== "undefined" ? message.redirect : false; + + $("") + .prependTo($(message.selector)) + .slideDown(800, function () { + if (message.redirect) { + setTimeout(function () { + location.href = typeof (message.postBack) !== "undefined" ? message.postBack : "/"; + }, 3000); + } + }); + }; + + let dismiss = function (alert, callback) { + let alertPanel = $(alert.selector).find(".alert-panel"); + + $.each(alertPanel, function (index, el) { + + $(el).slideUp(800, function () { + $(el).remove(); + + if (typeof (callback) === "function") { + callback(); + } + }); + }); + + if (alertPanel.length == 0 && typeof (callback) === "function") { + callback(); + } + }; + + return { + success: success, + info: info, + warning: warning, + danger: danger, + dismiss: dismiss + }; +}; diff --git a/generators/spa/templates/common/src/Resources/scripts/useFetch.js b/generators/spa/templates/common/src/Resources/scripts/useFetch.js new file mode 100644 index 00000000..80311b9e --- /dev/null +++ b/generators/spa/templates/common/src/Resources/scripts/useFetch.js @@ -0,0 +1,47 @@ +import { useState, useEffect } from "react"; + +const useFetch = (url) => { + const [data, setData] = useState(null); + const [isPending, setIsPending] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const abortCont = new AbortController(); + fetch(url,{ + method: "GET", + headers: { + "ModuleId": 389, + "RequestVerificationToken": "vt4k-ZjhQv_b6yTjs5I0DhumWcY_8sMm52euNE-MzEFLJVg3EtMu5GkKRGtWCgowSCPA58POdpzdprZA0", + "TabId": 36 + }, + signal: abortCont.signal + }) + .then(res => { + if (!res.ok) { // error coming back from server + throw Error("could not fetch the data for that resource"); + } + return res.json(); + }) + .then(data => { + setIsPending(false); + setData(data); + setError(null); + }) + .catch(err => { + if (err.name === "AbortError") { + console.log("fetch aborted"); + } else { + // auto catches network / connection error + setIsPending(false); + setError(err.message); + } + }); + + // abort the fetch + return () => abortCont.abort(); + }, [url]); + + return { data, isPending, error }; +}; + +export default useFetch; \ No newline at end of file From c87123ebeb72a020f3a31a16f31e14a0123f438a Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 04:05:40 +0100 Subject: [PATCH 19/27] Create Constants.cs --- generators/spa/templates/common/Constants.cs | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 generators/spa/templates/common/Constants.cs diff --git a/generators/spa/templates/common/Constants.cs b/generators/spa/templates/common/Constants.cs new file mode 100644 index 00000000..f46e659e --- /dev/null +++ b/generators/spa/templates/common/Constants.cs @@ -0,0 +1,27 @@ +/* +Copyright Upendo Ventures, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +namespace <%= fullNamespace %> +{ + public static class QuickSettings + { + public const string MODSETTING_Name = "Name"; + public const string MODSETTING_Description = "Description"; + public const string MODSETTING_ItemId = "ItemId"; + public const string MODSETTING_AssignedUserId = "AssignedUserId"; + public const string MODSETTING_CreatedByUserId = "CreatedByUserId"; + public const string MODSETTING_CreatedOnDate = "CreatedOnDate"; + } +} \ No newline at end of file From 4a7b75a97dcc89a7a4fa13f650010115ea955a62 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 04:05:50 +0100 Subject: [PATCH 20/27] update settings --- generators/spa/templates/ReactJS/common/Module.csproj | 9 +++++++-- .../common/src/Resources/scripts/QuickSettings.js | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/generators/spa/templates/ReactJS/common/Module.csproj b/generators/spa/templates/ReactJS/common/Module.csproj index bd985563..feed85ac 100644 --- a/generators/spa/templates/ReactJS/common/Module.csproj +++ b/generators/spa/templates/ReactJS/common/Module.csproj @@ -114,18 +114,23 @@ - - + + + + + + + diff --git a/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js b/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js index 0d55476a..3ce532c1 100644 --- a/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js +++ b/generators/spa/templates/common/src/Resources/scripts/QuickSettings.js @@ -7,7 +7,7 @@ dnnspamodule.quickSettings = function (root, moduleId) { let parentSelector = "[id='" + root + "']"; // Setup your settings service endpoint let service = { - baseUrl: "DesktopModules/React7/API/", + baseUrl: "DesktopModules/<%= moduleName %>/API/", framework: $.ServicesFramework(moduleId), controller: "Settings" }; From 4cf47d16add873e074848043670aaaee4cbd042c Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 13:32:37 +0100 Subject: [PATCH 21/27] Update index.js --- generators/spa/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generators/spa/index.js b/generators/spa/index.js index 5ba70a3c..30d0b2ba 100644 --- a/generators/spa/index.js +++ b/generators/spa/index.js @@ -223,6 +223,12 @@ module.exports = class extends DnnGeneratorBase { this.destinationPath(moduleName + '/RouteConfig.cs'), template ); + + this.fs.copyTpl( + this.templatePath('common/Constants.cs'), + this.destinationPath(moduleName + '/Constants.cs'), + template + ); this.fs.copyTpl( this.templatePath('common/manifest.dnn'), From 48e147c3acab6a21d73e2188fd0026fb271dae66 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 13:32:39 +0100 Subject: [PATCH 22/27] Update Module.csproj --- generators/spa/templates/ReactJS/common/Module.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/generators/spa/templates/ReactJS/common/Module.csproj b/generators/spa/templates/ReactJS/common/Module.csproj index feed85ac..fc6f669e 100644 --- a/generators/spa/templates/ReactJS/common/Module.csproj +++ b/generators/spa/templates/ReactJS/common/Module.csproj @@ -125,6 +125,7 @@ + From 136b3f93ad26e92026f3bec1ae6b41ad85b2ac49 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 13:47:23 +0100 Subject: [PATCH 23/27] Create License.txt --- generators/spa/templates/common/License.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 generators/spa/templates/common/License.txt diff --git a/generators/spa/templates/common/License.txt b/generators/spa/templates/common/License.txt new file mode 100644 index 00000000..ea13267a --- /dev/null +++ b/generators/spa/templates/common/License.txt @@ -0,0 +1,3 @@ +

<%= moduleName %> Modules Extension for DNN

+

<%= company %> <%= companyUrl %>

+

Your License Here

From 1171c3d5c0d62dd8c249f001faece1984cea90d2 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 13:47:25 +0100 Subject: [PATCH 24/27] Create ReleaseNotes.txt --- generators/spa/templates/common/ReleaseNotes.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 generators/spa/templates/common/ReleaseNotes.txt diff --git a/generators/spa/templates/common/ReleaseNotes.txt b/generators/spa/templates/common/ReleaseNotes.txt new file mode 100644 index 00000000..c85f014c --- /dev/null +++ b/generators/spa/templates/common/ReleaseNotes.txt @@ -0,0 +1,10 @@ +

<%= moduleName %>

+

+ <%= company %>
+ <%= emailAddy %> +

+
+
+

About the <%= moduleName %>

+

This module is intended as an example of how to build DNN Modules with VueJS.

+
From 051da4279008322470f2edb30a8c5abc821d8c5b Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 13:47:29 +0100 Subject: [PATCH 25/27] Update Module.csproj --- generators/spa/templates/ReactJS/common/Module.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/generators/spa/templates/ReactJS/common/Module.csproj b/generators/spa/templates/ReactJS/common/Module.csproj index fc6f669e..e23c433c 100644 --- a/generators/spa/templates/ReactJS/common/Module.csproj +++ b/generators/spa/templates/ReactJS/common/Module.csproj @@ -142,14 +142,6 @@
- - - web.config - - - web.config - - 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) From 2307982652e3d6d150d3bd3d58b952505b059abd Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 14:00:56 +0100 Subject: [PATCH 26/27] Update index.js --- generators/spa/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/generators/spa/index.js b/generators/spa/index.js index 30d0b2ba..57ba7749 100644 --- a/generators/spa/index.js +++ b/generators/spa/index.js @@ -241,6 +241,18 @@ module.exports = class extends DnnGeneratorBase { this.destinationPath(moduleName + '/' + moduleName + '_Symbols.dnn'), template ); + + this.fs.copyTpl( + this.templatePath('common/License.txt'), + this.destinationPath(moduleName + '/License.txt'), + template + ); + + this.fs.copyTpl( + this.templatePath('common/ReleaseNotes.txt'), + this.destinationPath(moduleName + '/ReleaseNotes.txt'), + template + ); this.fs.copyTpl( this.templatePath(spaType + '/common/Module.csproj'), From 109ca4b3f677581d4c9159512a672003bf3236e0 Mon Sep 17 00:00:00 2001 From: VAlmea Date: Tue, 7 Feb 2023 14:01:01 +0100 Subject: [PATCH 27/27] Update Module.csproj --- generators/spa/templates/ReactJS/common/Module.csproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/generators/spa/templates/ReactJS/common/Module.csproj b/generators/spa/templates/ReactJS/common/Module.csproj index e23c433c..862151ec 100644 --- a/generators/spa/templates/ReactJS/common/Module.csproj +++ b/generators/spa/templates/ReactJS/common/Module.csproj @@ -115,7 +115,7 @@ - + @@ -133,9 +133,6 @@ - - -