Compare commits

...

2291 Commits

Author SHA1 Message Date
05d2096fb8 Update README.md 2025-03-12 14:34:31 -04:00
7683af81bc Update README.md 2025-03-12 14:22:43 -04:00
bad10b3812 6.1.1 Release
6.1.1 Release
2025-03-12 14:21:41 -04:00
9f9522c2ed 6.1.1 Release
6.1.1 Release
2025-03-12 14:21:15 -04:00
62879c3e52 Merge pull request #5162 from sbwalker/dev
upgrade to .NET 9.0.3
2025-03-11 14:36:14 -04:00
45610f8dd7 upgrade to .NET 9.0.3 2025-03-11 14:35:59 -04:00
18102cbd78 Merge pull request #5160 from sbwalker/dev
sort endpoints by route
2025-03-11 13:11:34 -04:00
262d6a1529 sort endpoints by route 2025-03-11 13:11:19 -04:00
1124ddaf90 Merge pull request #5157 from zyhfish/task/fix-5156
Fix #5156: update the bind event to oninput.
2025-03-11 11:51:38 -04:00
981add3872 Merge pull request #5158 from sbwalker/dev
rename Cache service to OutputCache
2025-03-11 11:48:58 -04:00
8d4b30140e rename Cache service to OutputCache 2025-03-11 11:48:43 -04:00
Ben
b9c59137a8 Fix #5156: update the bind event to oninput. 2025-03-11 22:58:06 +08:00
0b1c7e06ca Update README.md 2025-03-10 10:56:41 -04:00
fcaf80cba6 Update README.md 2025-03-10 10:56:11 -04:00
6358b9eabb Merge pull request #5155 from sbwalker/dev
added Logout Everywhere option to User Settings
2025-03-10 10:53:25 -04:00
70a3fab1ff added Logout Everywhere option to User Settings 2025-03-10 10:53:05 -04:00
bdf86ace86 Merge pull request #5152 from sbwalker/dev
upgrade to ImageSharp 3.1.7 due to security vulnerability
2025-03-07 14:17:02 -05:00
d57132d1e4 upgrade to ImageSharp 3.1.7 due to security vulnerability 2025-03-07 14:16:47 -05:00
a6e87abf99 Merge pull request #5151 from sbwalker/dev
allow site settings to be overidden at host level
2025-03-07 14:15:31 -05:00
f1771610fe allow site settings to be overidden at host level 2025-03-07 14:15:16 -05:00
a88ea9780f Update README.md 2025-03-06 15:45:30 -05:00
bca0866d72 Update README.md 2025-03-06 15:43:59 -05:00
cebed93abf Update README.md 2025-03-06 15:42:48 -05:00
ee2b2e3569 Update README.md 2025-03-06 15:40:07 -05:00
cb8e9ee244 Update README.md 2025-03-06 15:38:18 -05:00
486184b16c Update README.md 2025-03-06 15:36:28 -05:00
9f9bd1988f Merge pull request #5149 from sbwalker/dev
update based on changes suggested by @adefwebserver
2025-03-06 15:25:37 -05:00
ba1bfd1bc0 update based on changes suggested by @adefwebserver 2025-03-06 15:25:25 -05:00
e12926e971 Merge pull request #5148 from sbwalker/dev
allow page and module settings to be included in site templates, improve terms and privacy default content, add Settings for HtmlText module
2025-03-06 14:46:38 -05:00
5b4db0de3b allow page and module settings to be included in site templates, improve terms and privacy default content, add Settings for HtmlText module 2025-03-06 14:46:17 -05:00
70ff55faa6 Merge pull request #5147 from sbwalker/dev
modify terminology
2025-03-06 09:43:55 -05:00
f2bd47d8bc modify terminology 2025-03-06 09:43:40 -05:00
e2b9c9e98e Merge pull request #5146 from sbwalker/dev
prepare for 6.1.1
2025-03-05 15:02:39 -05:00
b0791a594f prepare for 6.1.1 2025-03-05 15:02:12 -05:00
ea5eaa6ed2 Merge pull request #5145 from sbwalker/dev
update to .NET 9.0.2
2025-03-05 14:55:00 -05:00
ec3fd1d585 update to .NET 9.0.2 2025-03-05 14:54:46 -05:00
d76de22977 Merge pull request #5144 from sbwalker/dev
modify localization text
2025-03-05 10:45:17 -05:00
c0e3483cc7 modify localization text 2025-03-05 10:44:34 -05:00
0994cdf3b6 Merge pull request #5141 from sbwalker/dev
sync interop.js changes with .NET MAUI
2025-03-04 16:25:24 -05:00
a76fd82262 sync interop.js changes with .NET MAUI 2025-03-04 16:25:10 -05:00
2f919c7d69 Merge pull request #5140 from sbwalker/dev
fix regression issue with Search component
2025-03-04 15:45:16 -05:00
f12592731b fix regression issue with Search component 2025-03-04 15:45:02 -05:00
4a20e1a25d Merge pull request #5138 from zyhfish/task/improve-middle-screen-view
improve the styles in middle screen size.
2025-03-04 15:42:37 -05:00
cc7111c3ff Merge pull request #5139 from sbwalker/dev
change module title for Terms
2025-03-04 15:40:58 -05:00
81972aed62 change module title for Terms 2025-03-04 15:40:44 -05:00
Ben
5e2092c6d4 improve the styles in middle screen size. 2025-03-04 23:31:21 +08:00
d136f8ac91 Merge pull request #5137 from sbwalker/dev
add nonce support
2025-03-03 16:49:41 -05:00
5b23917940 add nonce support 2025-03-03 16:49:28 -05:00
2cda0a3798 Merge pull request #5136 from sbwalker/dev
modify cookie consent text
2025-03-03 15:37:46 -05:00
f315ad1ce9 modify cookie consent text 2025-03-03 15:37:31 -05:00
49f1c273c2 Merge pull request #5134 from sbwalker/dev
add terms to upgrademanager
2025-03-03 13:36:47 -05:00
8518476c87 add terms to upgrademanager 2025-03-03 13:36:32 -05:00
a34ed756db Merge pull request #5132 from mdmontesinos/sitemap-cache
resolves #4899: output cache for sitemap
2025-03-03 13:22:46 -05:00
a48232c4e3 Merge pull request #5133 from sbwalker/dev
add default privacy and terms
2025-03-03 13:22:33 -05:00
ac65e38390 add default privacy and terms 2025-03-03 13:22:17 -05:00
eab3a753f5 resolves #4899: output cache for sitemap 2025-03-03 17:54:33 +01:00
9e5922e121 Merge pull request #5130 from zyhfish/task/fix-4936
Fix #4936: set the allow cookie value when refresh state.
2025-03-03 07:57:42 -05:00
Ben
bf57b23776 update the page state after policy changed. 2025-03-01 15:05:23 +08:00
Ben
8f4a20fd46 Fix #4936: set the allow cookie value when refresh state. 2025-03-01 14:16:42 +08:00
b3716da5ac Merge pull request #5128 from zyhfish/task/fix-4936-new
move the styles to app.css.
2025-02-28 13:36:58 -05:00
2c129fd800 Merge pull request #5129 from sbwalker/dev
localization text change
2025-02-28 13:36:49 -05:00
6fb18e7a25 localization text change 2025-02-28 13:36:34 -05:00
Ben
38d28d6944 move the styles to app.css. 2025-02-28 23:53:53 +08:00
a187e1a7a2 Merge pull request #5127 from sbwalker/dev
fix RESX issue
2025-02-28 10:52:18 -05:00
7d7a19c7c2 fix RESX issue 2025-02-28 10:52:06 -05:00
6a2ae2153a Merge pull request #5119 from zyhfish/task/fix-4936
update the cookie consent control.
2025-02-28 10:48:21 -05:00
f50ba1a91e Merge branch 'dev' into task/fix-4936 2025-02-28 10:47:24 -05:00
b09575dbd6 Merge pull request #5126 from sbwalker/dev
provide option to assign a theme to a site
2025-02-28 10:45:40 -05:00
c52ee3d91d provide option to assign a theme to a site 2025-02-28 10:45:25 -05:00
Ben
1ced5c0425 update the cookie consent control. 2025-02-28 23:32:17 +08:00
e399a5c9b1 Merge pull request #5124 from sbwalker/dev
add missing maxlength attributes
2025-02-27 10:51:37 -05:00
08dff5fb67 add missing maxlength attributes 2025-02-27 10:51:22 -05:00
912760f2a7 Update SECURITY.md 2025-02-26 15:29:49 -05:00
4b62fdbf93 Update SECURITY.md 2025-02-26 15:27:33 -05:00
df593d43a7 Update SECURITY.md 2025-02-26 15:25:25 -05:00
89b1fba771 Merge pull request #5123 from sbwalker/dev
remove package validation logic
2025-02-26 12:54:06 -05:00
5505c91ae0 remove package validation logic 2025-02-26 12:53:53 -05:00
cc720ff399 Merge pull request #5122 from sbwalker/dev
remove unnecessary log message
2025-02-26 12:12:14 -05:00
29f07f6c56 remove unnecessary log message 2025-02-26 12:11:56 -05:00
a69e197a1f Merge pull request #5121 from zyhfish/task/fix-5116
Fix #5116: parse the value as UTC time.
2025-02-26 07:45:55 -05:00
Ben
6dddd8eff8 only allow essential cookies when cookie consent not granted. 2025-02-26 19:41:58 +08:00
Ben
51aada8922 Fix #5116: parse the value as UTC time. 2025-02-26 18:25:24 +08:00
Ben
b47bf40e8f update the cookie consent control. 2025-02-25 11:36:47 +08:00
48151bf365 Merge pull request #5118 from sbwalker/dev
remove IJSRuntime reference as it was causing a compilation warning
2025-02-24 16:15:51 -05:00
659950996d remove IJSRuntime reference as it was causing a compilation warning 2025-02-24 16:15:35 -05:00
6e656a4d0a Merge pull request #5114 from zyhfish/task/fix-4936
Fix #4936: add the cookie consent theme control.
2025-02-24 16:08:22 -05:00
Ben
bf308dd13d enable child component of cookie consent control. 2025-02-24 22:32:19 +08:00
Ben
982f3b1943 Fix #4936: add the cookie consent theme control. 2025-02-22 09:49:33 +08:00
7a4ea8cf1b Merge pull request #5094 from zyhfish/task/set-fa-ir-culture
Fix #5054: resolve the issue in fa-IR language.
2025-02-19 07:36:16 -05:00
7c0482a87c Merge pull request #5111 from sbwalker/dev
remove warning message related to no jobs being registered
2025-02-18 11:50:57 -05:00
101ededd89 remove warning message related to no jobs being registered 2025-02-18 11:50:36 -05:00
a8cbc0040e Merge pull request #5108 from zyhfish/task/fix-5103
Fix #5103: return a copy of the assembly list.
2025-02-18 11:40:30 -05:00
ed91bb445b Merge pull request #5110 from sbwalker/dev
improve HostedServiceBase so that scheduled jobs can be registered during installation
2025-02-18 11:36:00 -05:00
f158a222f4 improve HostedServiceBase so that scheduled jobs can be registered during installation 2025-02-18 11:35:38 -05:00
46bcad1fca Merge pull request #5109 from sbwalker/dev
clean up scheduled jobs which have been uninstalled
2025-02-18 09:12:48 -05:00
5e147afb9f clean up scheduled jobs which have been uninstalled 2025-02-18 09:12:26 -05:00
Ben
b061d4593f Fix #5103: return a copy of the assembly list. 2025-02-18 22:02:25 +08:00
3fa520b4ef Merge pull request #5107 from sbwalker/dev
make purge job output more readable
2025-02-18 08:53:38 -05:00
2df05b4afd make purge job output more readable 2025-02-18 08:53:23 -05:00
e0569a6748 Merge pull request #5104 from sbwalker/dev
fix visitor purge logic
2025-02-17 13:22:11 -05:00
2e6ab398d9 fix visitor purge logic 2025-02-17 13:21:58 -05:00
Ben
94b03d2a6b update settings for all RTL languages. 2025-02-16 10:25:43 +08:00
f84fe30bb6 Merge pull request #5097 from sbwalker/dev
synchronize BlazorScriptReload changes
2025-02-14 09:17:58 -05:00
049ddef531 synchronize BlazorScriptReload changes 2025-02-14 09:17:44 -05:00
a1a214c742 Merge pull request #5096 from sbwalker/dev
add another constructor for Script class
2025-02-14 09:09:14 -05:00
c40a483ffa add another constructor for Script class 2025-02-14 09:09:00 -05:00
Ben
aff99acfae Fix #5054: resolve the issue in fa-IR language. 2025-02-12 20:18:10 +08:00
628129c08d Update README.md 2025-02-11 12:00:41 -05:00
679d34dfdf Merge pull request #5093 from oqtane/master
6.1.0 Release
2025-02-11 11:49:29 -05:00
b2f65903ae Merge pull request #5092 from oqtane/dev
6.1.0 Release
2025-02-11 11:49:06 -05:00
2daefe0382 Merge pull request #5091 from tvatavuk/patch-1
Minor fix in ThemeController.cs
2025-02-11 11:41:52 -05:00
1214a11704 Minor fix in ThemeController.cs
update `SharedReference` to use "Oqtane.Shared" for PackageReference code
2025-02-11 14:35:13 +01:00
e55e0118c2 Merge pull request #5090 from sbwalker/dev
fix #5089 - remove upgrade cleanup logic as .NET 9.0.1 moves assemblies back to /bin folder
2025-02-10 16:53:42 -05:00
a1ac81e907 fix #5089 - remove upgrade cleanup logic as .NET 9.0.1 moves assemblies back to /bin folder 2025-02-10 16:53:22 -05:00
14ad68bf69 Merge pull request #5088 from sbwalker/dev
modify RemoveAssemblies method so that it only runs once - not for every tenant
2025-02-10 16:27:24 -05:00
e3118c6e99 modify RemoveAssemblies method so that it only runs once - not for every tenant 2025-02-10 16:27:05 -05:00
b41aeab8f8 Merge pull request #5087 from sbwalker/dev
update Provider property to Pomelo
2025-02-10 10:47:07 -05:00
1a738b358e update Provider property to Pomelo 2025-02-10 10:46:44 -05:00
f4b1e8035b Merge pull request #5086 from sbwalker/dev
improve notification add and update methods
2025-02-10 09:50:35 -05:00
324e985247 improve notification add and update methods 2025-02-10 09:50:21 -05:00
60faacd7d0 Merge pull request #5085 from sbwalker/dev
fix comment
2025-02-10 08:21:13 -05:00
d4a4d7c346 fix comment 2025-02-10 08:20:58 -05:00
189f8f1d27 Merge pull request #5082 from sbwalker/dev
enhance purge job to trim broken urls based on retention policy
2025-02-09 13:02:21 -05:00
ed353461da enhance purge job to trim broken urls based on retention policy 2025-02-09 13:02:07 -05:00
e9330d6c62 Merge pull request #5080 from zyhfish/task/fix-5079
Fix #5079: Retrieve all Url Mapping records
2025-02-09 12:35:28 -05:00
f53e7cc3f6 Merge pull request #5081 from sbwalker/dev
fix #5072 - administrators should be allowed to send system notifications
2025-02-09 12:34:38 -05:00
4f4258d532 fix #5072 - administrators should be allowed to send system notifications 2025-02-09 12:34:17 -05:00
Ben
c80910f355 Fix #5079: remove the records limit. 2025-02-08 11:51:38 +08:00
12470ab178 Merge pull request #5075 from mdmontesinos/dev
fix #5074: generate cancellation token for file upload
2025-02-07 07:53:16 -05:00
704e091e9b Merge pull request #5076 from sbwalker/dev
synchronize interop script changes with .NET MAUI
2025-02-07 07:52:58 -05:00
f30f1e5c1f synchronize interop script changes with .NET MAUI 2025-02-07 07:52:43 -05:00
0741ce2197 fix #5074: generate cancellation token for file upload 2025-02-07 09:11:52 +01:00
fc81bae9b7 Update README.md 2025-02-06 15:16:50 -05:00
3fa68e4f96 Merge pull request #5071 from sbwalker/dev
moved file setting to File Management and added Max Chunk Size
2025-02-06 15:10:29 -05:00
05a767c7be moved file setting to File Management and added Max Chunk Size 2025-02-06 15:10:14 -05:00
8c1e8f6377 Merge pull request #5070 from sbwalker/dev
fix #5067 - add support for Guid data types
2025-02-06 14:17:06 -05:00
0fbae8d7da fix #5067 - add support for Guid data types 2025-02-06 14:16:53 -05:00
cec4b339f5 Merge pull request #5069 from mdmontesinos/dev-test
fix #5058: ensure sequential file and chunk uploads to avoid overload
2025-02-06 13:56:35 -05:00
1a7656d8ee fix #5058: ensure sequential file and chunk uploads to avoid overload 2025-02-06 19:21:51 +01:00
e173815810 Merge pull request #5068 from sbwalker/dev
fix LogLevel for file upload error
2025-02-06 12:21:51 -05:00
620c768e05 fix LogLevel for file upload error 2025-02-06 12:21:34 -05:00
7740679077 Merge pull request #5066 from sbwalker/dev
fix #5061 - configure Page Management for personalizable pages
2025-02-06 11:16:46 -05:00
1ebc8ebff3 fix #5061 - configure Page Management for personalizable pages 2025-02-06 11:16:30 -05:00
fa4fac70d5 Merge pull request #5065 from sbwalker/dev
improve file upload validation and error handling on server
2025-02-06 08:20:13 -05:00
8c83a18f93 improve file upload validation and error handling on server 2025-02-06 08:19:57 -05:00
a151ecfda0 Merge pull request #5064 from sbwalker/dev
modified file upload error message to reflect new behavior
2025-02-05 19:10:10 -05:00
dec0c0649c modified file upload error message to reflect new behavior 2025-02-05 19:09:55 -05:00
a356f893ac Merge pull request #5063 from sbwalker/dev
remove uploadFile() method as it is not used
2025-02-05 17:08:56 -05:00
e2af4f74c3 remove uploadFile() method as it is not used 2025-02-05 17:08:32 -05:00
99022b76e5 Merge pull request #5062 from sbwalker/dev
file upload improvements
2025-02-05 16:48:59 -05:00
9dd6dc7523 file upload improvements 2025-02-05 16:48:34 -05:00
6f588200d7 Merge pull request #5057 from sbwalker/dev
fix #5044 - improve file part removal logic
2025-02-03 11:00:37 -05:00
f3dbeae28e fix #5044 - improve file part removal logic 2025-02-03 11:00:22 -05:00
9f70361298 Merge pull request #5056 from sbwalker/dev
add additional Script class constructors
2025-02-03 10:35:32 -05:00
534353ce13 add additional Script class constructors 2025-02-03 10:35:17 -05:00
3f391a7354 Merge pull request #5052 from sbwalker/dev
modify button spacing
2025-01-31 14:51:06 -05:00
0dd0752710 modify button spacing 2025-01-31 14:50:54 -05:00
710fae4b0e Merge pull request #5051 from sbwalker/dev
add user impersonation
2025-01-31 11:14:28 -05:00
de6c57a7ee add user impersonation 2025-01-31 11:14:13 -05:00
7eee1fcd6a Merge pull request #5050 from sbwalker/dev
make Kestrel the default profile in launchjSettings.json
2025-01-31 09:18:59 -05:00
1fd2aedf96 make Kestrel the default profile in launchjSettings.json 2025-01-31 09:18:44 -05:00
ffdd7c063b Merge pull request #5049 from sbwalker/dev
added a ScriptsLoaded property in ModuleBase and ThemeBase for flow control in Interactive rendering scenarios
2025-01-31 08:42:56 -05:00
a87af264eb added a ScriptsLoaded property in ModuleBase and ThemeBase for flow control in Interactive rendering scenarios 2025-01-31 08:42:36 -05:00
3640cd2fdd Merge pull request #5046 from sbwalker/dev
fix upgrade issue which can occur in development environments
2025-01-30 08:40:08 -05:00
f7cf25c4bb fix upgrade issue which can occur in development environments 2025-01-30 08:39:49 -05:00
77dbd0d4c7 Merge pull request #5045 from sbwalker/dev
update version to 6.1.0
2025-01-30 08:08:34 -05:00
5a77c83e68 update version to 6.1.0 2025-01-30 08:08:16 -05:00
0a6763e08c Merge pull request #5043 from sbwalker/dev
change ResourceLoadBehavior Never to None
2025-01-29 19:05:20 -05:00
b5aa206670 change ResourceLoadBehavior Never to None 2025-01-29 19:05:05 -05:00
dbb4d9b64b Merge pull request #5042 from sbwalker/dev
fix logic to retrieve access token
2025-01-29 16:03:11 -05:00
6775edfd66 fix logic to retrieve access token 2025-01-29 16:02:55 -05:00
b06750ed65 Merge pull request #5040 from sbwalker/dev
remove method which was relocated to PageRepository
2025-01-29 13:12:59 -05:00
57879c1891 remove method which was relocated to PageRepository 2025-01-29 13:12:46 -05:00
65b55a76f2 Merge pull request #5039 from sbwalker/dev
improve asset caching help text
2025-01-29 12:40:02 -05:00
8562a68306 improve asset caching help text 2025-01-29 12:39:47 -05:00
160da46b5a Merge pull request #5038 from sbwalker/dev
remove Environment.IsDevelopment logic
2025-01-29 12:27:57 -05:00
ae5f70a739 remove Environment.IsDevelopment logic 2025-01-29 12:27:42 -05:00
4456e57466 Merge pull request #5036 from sbwalker/dev
use fingerprint term consistently
2025-01-29 10:42:34 -05:00
24cd090c61 use fingerprint term consistently 2025-01-29 10:42:19 -05:00
4f849f5d5f Merge pull request #5035 from sbwalker/dev
performance improvement when loading files within a folder
2025-01-29 10:23:11 -05:00
db2e86e84c performance improvement when loading files within a folder 2025-01-29 10:22:56 -05:00
14748ce2b3 Merge pull request #5034 from sbwalker/dev
use Configuration service as it already exists
2025-01-29 08:28:08 -05:00
527509732c use Configuration service as it already exists 2025-01-29 08:22:21 -05:00
aa9214477c Merge pull request #5033 from sbwalker/dev
fix #5018 - redirect file download to login page
2025-01-28 16:31:03 -05:00
db24ed8b55 fix #5018 - redirect file download to login page 2025-01-28 16:30:49 -05:00
349d1849d9 Merge pull request #5032 from sbwalker/dev
use deterministic hash in file server image generation
2025-01-28 15:55:56 -05:00
188be2fa8c use deterministic hash in file server image generation 2025-01-28 15:55:40 -05:00
5c4d7df734 Merge pull request #5031 from sbwalker/dev
remove Oqtane.Server.staticwebassets.endpoints.json from release packages
2025-01-28 14:39:48 -05:00
37de18c670 remove Oqtane.Server.staticwebassets.endpoints.json from release packages 2025-01-28 14:39:30 -05:00
0001e3844b Merge pull request #5030 from sbwalker/dev
provides options to control caching for static assets
2025-01-28 14:30:13 -05:00
65f171f701 provides options to control caching for static assets 2025-01-28 14:29:58 -05:00
c4308c239c Merge pull request #5007 from RahulKaushik007/fix-static-file-caching
Fixes #5005: Add Browser Caching for Static Assets
2025-01-28 13:21:29 -05:00
2b6af3cb37 Merge pull request #5029 from sbwalker/dev
fix localization text
2025-01-28 13:18:32 -05:00
c5a16fbbc1 fix localization text 2025-01-28 13:18:18 -05:00
1db83f509b Merge pull request #5028 from sbwalker/dev
add caching support for folders
2025-01-28 12:47:37 -05:00
2a06304a2c add caching support for folders 2025-01-28 12:47:23 -05:00
7bbe684135 Merge pull request #5027 from sbwalker/dev
improve terminology consistency
2025-01-28 08:56:19 -05:00
a996a88fc4 improve terminology consistency 2025-01-28 08:56:05 -05:00
8cf9e7db51 Merge pull request #5026 from sbwalker/dev
add Fingerprint property to ModuleBase and ThemeBase
2025-01-28 08:44:01 -05:00
ed981c67b7 add Fingerprint property to ModuleBase and ThemeBase 2025-01-28 08:43:48 -05:00
6a77a0a5b9 Merge pull request #5025 from sbwalker/dev
improve terminology
2025-01-28 08:34:31 -05:00
bfb4b4431b improve terminology 2025-01-28 08:34:15 -05:00
3de44c0335 Merge pull request #5024 from sbwalker/dev
add ThemeState property to ThemeBase
2025-01-28 08:27:25 -05:00
37afd1aec9 add ThemeState property to ThemeBase 2025-01-28 08:27:10 -05:00
b2ac561673 Merge pull request #5021 from thabaum/update-package-dependencies-9.0.1
Fixes #5020: Updates package dependencies 9.0.1 (Latest)
2025-01-27 16:44:33 -05:00
c9bf7d9138 Merge pull request #5022 from sbwalker/dev
fix #5005 - adds versioning (ie. fingerprinting) for static assets - core, modules, and themes.
2025-01-27 16:35:07 -05:00
153a689bdb fix #5005 - adds versioning (ie. fingerprinting) for static assets - core, modules, and themes. 2025-01-27 16:34:47 -05:00
26b88f1a22 Update Package Dependencies to 9.0.1 2025-01-27 05:13:31 -08:00
c66a5d028f Update Package Dependencies to 9.0.1 2025-01-27 05:13:01 -08:00
8441c95a5c Update Package Dependencies to 9.0.1 2025-01-27 05:11:49 -08:00
e0e32b0199 Update Package Dependencies to 9.0.1 and 9.0.30 2025-01-27 05:09:19 -08:00
2bb76564e9 Update Package Dependencies to 9.0.1 2025-01-27 05:06:46 -08:00
86ec25d4de Update Package Dependencies to 9.0.1 2025-01-27 05:05:42 -08:00
ed9929963c Update Package Dependencies to 9.0.1 2025-01-27 05:04:34 -08:00
36f50118ac Update Package Dependencies to 9.0.1 2025-01-27 05:03:46 -08:00
72ddf27504 Update Package Dependency to 9.2.0 2025-01-27 05:03:03 -08:00
9bd36931ff Update Package Dependencies to 9.0.1 2025-01-27 05:02:10 -08:00
056ef7a3d5 Update Package Dependencies to 9.0.1 2025-01-27 05:00:08 -08:00
e483945d05 Merge pull request #5017 from sbwalker/dev
fix #5014 - page content scripts not loading on initial page request in Interactive rendering
2025-01-24 14:29:42 -05:00
7a9c637e03 fix #5014 - page content scripts not loading on initial page request in Interactive rendering 2025-01-24 14:29:23 -05:00
09ce543ea6 Merge pull request #5013 from sbwalker/dev
allow packages to be managed across installations
2025-01-23 09:08:16 -05:00
0ef24ebc3f allow packages to be managed across installations 2025-01-23 09:08:02 -05:00
a4419d3af6 Merge pull request #5011 from sbwalker/dev
remove GetButtonSize method
2025-01-22 07:43:38 -05:00
935983c02a remove GetButtonSize method 2025-01-22 07:43:23 -05:00
bd54ce5017 Merge pull request #4998 from leigh-pointer/ActionDialogSize
Update ActionDialog Add method to ensure consistent button sizing
2025-01-22 07:42:04 -05:00
af6ed78b8e Update ActionDialog.razor 2025-01-22 07:57:52 +01:00
f72438996d Merge remote-tracking branch 'upstream/dev' into ActionDialogSize 2025-01-22 07:36:01 +01:00
9db2a55a5a Merge pull request #5010 from sbwalker/dev
fix #4964 - use bearer token if it already exists
2025-01-21 16:55:19 -05:00
950d90badb fix #4964 - use bearer token if it already exists 2025-01-21 16:55:02 -05:00
1864d180af Merge pull request #5003 from sdi2121/patch-1
Update Oqtane.Server.csproj - MySQL deploy to Azure error
2025-01-21 15:58:44 -05:00
0e82e98382 Merge pull request #5006 from mdmontesinos/patch-1
FIX: File server MimeType not updated after image conversion
2025-01-21 15:58:33 -05:00
46023d35dc Merge pull request #5009 from sbwalker/dev
fix #4976 - manage hierarchical path updates and page deletion
2025-01-21 15:58:08 -05:00
90d2e0a40b fix #4976 - manage hierarchical path updates and page deletion 2025-01-21 15:57:48 -05:00
5f884e0796 Merge pull request #5008 from sbwalker/dev
fix #4965 - improve user/site management
2025-01-21 12:21:50 -05:00
16477052e2 fix #4965 - improve user/site management 2025-01-21 12:21:27 -05:00
66a05603f7 Fix static file caching headers 2025-01-21 17:42:08 +05:30
fe2a883386 Fix static file caching headers 2025-01-21 17:26:47 +05:30
ca7fdaa125 FIX: File server MimeType not updated after image conversion 2025-01-20 12:17:22 +01:00
1283ec2008 Update Oqtane.Server.csproj
Fixes Azure manual deployment build from local code build. May need an additional fix in MySQL library (Line 24 - MySQLDatabase.cs)
2025-01-18 13:53:04 -05:00
d1f78f9048 Update LICENSE 2025-01-17 12:57:32 -05:00
45f43bfade Merge pull request #5002 from sbwalker/dev
update copyright year
2025-01-17 12:57:14 -05:00
4793ab4bc9 update copyright year 2025-01-17 12:56:59 -05:00
88b174dea8 Merge pull request #5001 from sbwalker/dev
remove unused method
2025-01-17 12:50:42 -05:00
06ca382bd7 remove unused method 2025-01-17 12:50:26 -05:00
b09175a8db Merge pull request #5000 from sbwalker/dev
allow entry of name during installation
2025-01-17 11:14:49 -05:00
677f68b08d allow entry of name during installation 2025-01-17 11:14:35 -05:00
8058b8dba4 Merge pull request #4999 from sbwalker/dev
improve error messages
2025-01-17 07:54:49 -05:00
4bc26f13c1 improve error messages 2025-01-17 07:54:34 -05:00
e6cf77e724 Update ActionDialog Add method to ensure consistent button sizing
This PR introduces a new private method GetButtonSize() to enhance the consistency of button sizing within our UI. The method specifically checks for the presence of the "btn-sm" class in the Action Button's class list and applies the same sizing to the Cancel Button if found.
2025-01-17 13:34:16 +01:00
f8737c112e Merge pull request #4997 from sbwalker/dev
reload the script if data-reload is "always" or if the script has not been loaded previously and data-reload is "once" or "true"
2025-01-16 15:06:36 -05:00
74b72ed9d4 reload the script if data-reload is "always" or if the script has not been loaded previously and data-reload is "once" or "true" 2025-01-16 15:06:15 -05:00
4950391201 Merge pull request #4996 from sbwalker/dev
allow data-reload to support true or always
2025-01-16 14:22:06 -05:00
64a38d6e45 allow data-reload to support true or always 2025-01-16 14:21:52 -05:00
e2d8ee53f8 Merge pull request #4995 from sbwalker/dev
script reload improvements
2025-01-16 14:06:28 -05:00
0204ff8dd5 script reload improvements 2025-01-16 14:06:13 -05:00
4630ee6e93 Merge pull request #4992 from beolafsen/dev
Trim ModuleOwner and ModuleName before create
2025-01-16 12:29:00 -05:00
c4f2abf143 Merge pull request #4994 from sbwalker/dev
fix #4986 - allow Resources which have Reload specified to be used in Interactive rendering
2025-01-16 12:26:30 -05:00
e7444a0194 fix #4986 - allow Resources which have Reload specified to be used in Interactive rendering 2025-01-16 12:26:10 -05:00
ffed7305ed Merge pull request #4993 from sbwalker/dev
fix #4984 - path mapping for personalized pages
2025-01-16 09:25:43 -05:00
334054bcd4 fix #4984 - path mapping for personalized pages 2025-01-16 09:25:27 -05:00
5bb98eb5b2 Trim ModuleOwner and ModuleName before create 2025-01-16 09:32:18 +01:00
e842bd882a Merge pull request #4991 from sbwalker/dev
fix #4984 - redirect not working for personalized pages
2025-01-15 11:57:00 -05:00
74bfb46f73 fix #4984 - redirect not working for personalized pages 2025-01-15 11:56:44 -05:00
cd45bf4b70 Merge pull request #4989 from sbwalker/dev
fix #4984 - ensure personalized page path does not contain illegal characters
2025-01-14 15:43:00 -05:00
51600bbcb0 fix #4984 - ensure personalized page path does not contain illegal characters 2025-01-14 15:42:40 -05:00
8811a9bcaa Merge pull request #4988 from sbwalker/dev
introduce RemoveAssemblies() method in UpgradeManager
2025-01-14 08:43:38 -05:00
4521f8a774 introduce RemoveAssemblies() method in UpgradeManager 2025-01-14 08:43:23 -05:00
5b427783f8 Merge pull request #4987 from zyhfish/task/fix-4954
Fix #4954: use Pomelo.EntityFrameworkCore.MySql package.
2025-01-14 08:34:34 -05:00
Ben
9508983b15 Fix #4954: use Pomelo.EntityFrameworkCore.MySql package. 2025-01-14 19:58:56 +08:00
fd09912cd7 Merge pull request #4978 from beolafsen/dev
Issue #4977
2025-01-13 16:00:06 -05:00
01cc8584b6 Merge pull request #4968 from leigh-pointer/unused
Removed unused Using statements from the SiteTemplates
2025-01-13 15:56:39 -05:00
c0b104e7c8 Merge pull request #4962 from thabaum/prepare-6.0.2-update-dependencies
Fixes #4961 - Updates Oqtane version to 6.0.2 and update related project dependencies to latest.
2025-01-13 15:55:13 -05:00
9a82021a82 Merge pull request #4983 from sbwalker/dev
include option for external login to save tokens
2025-01-13 15:14:27 -05:00
1fb54a0b0f include option for external login to save tokens 2025-01-13 15:14:13 -05:00
aa5ea61638 Merge pull request #4982 from sbwalker/dev
improve filtering logic in UserRole API
2025-01-13 14:42:36 -05:00
a59ec0258b improve filtering logic in UserRole API 2025-01-13 14:42:19 -05:00
b403f5cf71 Merge pull request #4980 from sbwalker/dev
fix comment spelling
2025-01-13 07:50:21 -05:00
0ac6a62b86 fix comment spelling 2025-01-13 07:50:05 -05:00
ed3743d3b6 Merge pull request #4979 from sbwalker/dev
fix #4969 - improve feedback and flow when connection string points to an invalid database
2025-01-13 07:48:50 -05:00
3468cba000 fix #4969 - improve feedback and flow when connection string points to an invalid database 2025-01-13 07:48:30 -05:00
5a4cdc5354 Issue #4977 2025-01-13 07:31:35 +01:00
af4e19a57e Removed unused Using statements from the SiteTemplates 2025-01-07 04:14:31 +01:00
26bb743679 Prepare 6.0.2 2024-12-31 10:37:27 -08:00
96cc726e22 Prepare 6.0.2 2024-12-31 10:35:00 -08:00
f4b00b01d0 Prepare 6.0.2 2024-12-31 10:34:21 -08:00
127b2ca86d Prepare 6.0.2 2024-12-31 10:32:09 -08:00
4b8b93e1b8 Prepare 6.0.2 2024-12-31 10:31:47 -08:00
3aea412fe9 Prepare 6.0.2 2024-12-31 10:31:23 -08:00
2aef96ad4f Prepare 6.0.2 2024-12-31 10:29:52 -08:00
ec0a77230c Prepare 6.0.2 2024-12-31 10:29:32 -08:00
b35e4bddd0 Prepare 6.0.2 2024-12-31 10:28:48 -08:00
aa32beb341 Update Oqtane.Shared.csproj 2024-12-31 10:28:32 -08:00
efafe89b42 Prepare 6.0.2 2024-12-31 10:26:45 -08:00
5ef2e49d9c Prepare 6.0.2 2024-12-31 10:25:34 -08:00
1cfbf61a30 Prepare 6.0.2 2024-12-31 10:23:15 -08:00
2bb5494b84 Prepare 6.0.2 2024-12-31 10:22:10 -08:00
e8a41ccb47 Prepare 6.0.2 2024-12-31 10:21:10 -08:00
7184f7f635 Prepare 6.0.2 and update package dependencies 2024-12-31 10:20:13 -08:00
cc5727b7fa Prepare 6.0.2 and update package dependencies 2024-12-31 10:16:35 -08:00
7f3d6ef6a5 Merge pull request #4959 from sbwalker/dev
fix #4957 - unable to login after password reset
2024-12-31 08:18:14 -05:00
44ce68097b fix #4957 - unable to login after password reset 2024-12-31 08:17:58 -05:00
d976cc6c19 Update SECURITY.md 2024-12-25 10:04:25 -05:00
d19d7d2a43 Merge pull request #4948 from zyhfish/task/fix-4947
Fix #4947: check the 2FA settings.
2024-12-24 08:46:43 -05:00
9bfaa02f97 Merge pull request #4953 from sbwalker/dev
add back System.Text.Json to Shared project (#4929)
2024-12-23 14:48:10 -05:00
2d9396b245 add back System.Text.Json to Shared project (#4929) 2024-12-23 14:47:17 -05:00
56e0da64ee Merge pull request #4952 from sbwalker/dev
updated default module template to use Service consistently
2024-12-23 14:10:07 -05:00
997e9213f2 updated default module template to use Service consistently 2024-12-23 14:09:54 -05:00
366569a23b Merge pull request #4951 from sbwalker/dev
update package references
2024-12-23 11:24:38 -05:00
36d5747b4f update package references 2024-12-23 11:24:24 -05:00
ea026c726c Merge pull request #4950 from sbwalker/dev
remove unnecessary reference to System.Text.Json in Shared project
2024-12-23 11:16:49 -05:00
1e71e32c74 remove unnecessary reference to System.Text.Json in Shared project 2024-12-23 11:16:34 -05:00
ed729bbd4f Merge pull request #4949 from sbwalker/dev
fix #4946 - allow administrators to access user roles via API
2024-12-23 09:27:04 -05:00
1a925221b7 fix #4946 - allow administrators to access user roles via API 2024-12-23 09:26:50 -05:00
Ben
af7b4db062 Fix #4947: check the 2FA settings. 2024-12-23 22:10:51 +08:00
cfefe35e3f Update README.md 2024-12-20 16:56:05 -05:00
8d7845a44d Merge pull request #4944 from oqtane/master
6.0.1 Release
2024-12-20 16:52:31 -05:00
3a15e6e5e9 Merge pull request #4943 from oqtane/dev
6.0.1 Release
2024-12-20 16:52:10 -05:00
3b8a51e855 Merge pull request #4942 from sbwalker/dev
fix reload script to use static array rather than a live HtmlCollection
2024-12-20 15:39:50 -05:00
f2cb34cc35 fix reload script to use static array rather than a live HtmlCollection 2024-12-20 15:39:35 -05:00
723ce62a34 Merge pull request #4940 from sbwalker/dev
write upgrade errors to log rather than console
2024-12-20 14:38:34 -05:00
2c9a2ea021 write upgrade errors to log rather than console 2024-12-20 14:38:21 -05:00
2be008d6d1 Merge pull request #4939 from sbwalker/dev
fix compilation issues in PR #4782
2024-12-20 12:36:24 -05:00
7fb51bdd0a fix compilation issues in PR #4782 2024-12-20 12:36:10 -05:00
abdbe3694f Merge pull request #4782 from thabaum/edit-add-page-scrolltotoppage-error
Fixes #4781: Adds Edit + Add Page ScrollToTopPage() On Settings Tab Form Error Messages
2024-12-20 12:26:55 -05:00
bd87e5012f Merge pull request #4938 from sbwalker/dev
fix documentation
2024-12-20 11:55:50 -05:00
55e18f2364 fix documentation 2024-12-20 11:55:35 -05:00
655e84072d Merge pull request #4937 from sbwalker/dev
use CompressionEnabled switch to disable static asset compression during publish - eliminates need to cleanup files manually in release.cmd
2024-12-20 11:46:52 -05:00
ab5409d5b6 use CompressionEnabled switch to disable static asset compression during publish - eliminates need to cleanup files manually in release.cmd 2024-12-20 11:46:30 -05:00
5a5da6486c Merge pull request #4933 from sbwalker/dev
remove *.br, *.gz files from wwwroot content folders in published release (as MapStaticAssets is not enabled)
2024-12-19 19:56:36 -05:00
7e99252429 remove *.br, *.gz files from wwwroot content folders in published release (as MapStaticAssets is not enabled) 2024-12-19 19:56:13 -05:00
10e0dcef8b Merge pull request #4931 from sbwalker/dev
ensure Pages collection is always returned in the same order by moving GetPagesHierarchy method to the repository
2024-12-19 14:45:34 -05:00
80c8433aad ensure Pages collection is always returned in the same order by moving GetPagesHierarchy method to the repository. 2024-12-19 14:45:12 -05:00
5b0ae372f8 Merge pull request #4930 from sbwalker/dev
add support for data-reload=false attribute in Interactive rendering
2024-12-19 13:04:59 -05:00
b5a1b529ab add support for data-reload=false attribute in Interactive rendering 2024-12-19 13:04:43 -05:00
af821dcd9a Merge pull request #4914 from leigh-pointer/userSettings
User Profile Update: Utilizing User Settings Object
2024-12-18 15:27:34 -05:00
10d3c81520 Merge pull request #4918 from leigh-pointer/ProjectNameTemplates
Implement Dynamic ProjectName Parameter Across Build Process
2024-12-18 15:27:24 -05:00
e3811b453a Merge pull request #4927 from sbwalker/dev
Improvements to add support for script type and data-* attributes. Also added Script and Stylesheet classes to simplify Resource declarations.
2024-12-18 15:16:16 -05:00
ca0fb05baa Improvements to add support for script type and data-* attributes. Also added Script and Stylesheet classes to simplify Resource declarations. 2024-12-18 15:15:54 -05:00
2b4b01bf6e Merge pull request #4926 from sbwalker/dev
always render page-script elements in body
2024-12-18 11:56:18 -05:00
3a1244bddc always render page-script elements in body 2024-12-18 11:56:03 -05:00
b8fd922b19 Merge pull request #4925 from sbwalker/dev
improve reload script to replicate all attributes
2024-12-18 10:32:12 -05:00
03f856025e improve reload script to replicate all attributes 2024-12-18 10:31:59 -05:00
45f04d24c3 Merge pull request #4924 from sbwalker/dev
refactor Static Blazor script processing
2024-12-18 10:09:20 -05:00
2435d610c7 refactor Static Blazor script processing 2024-12-18 10:09:02 -05:00
06572bcd14 Merge pull request #4922 from sbwalker/dev
page-script optimization
2024-12-17 14:57:17 -05:00
3fab79afc0 page-script optimization 2024-12-17 14:57:01 -05:00
2b7dd3fed5 Merge pull request #4921 from sbwalker/dev
render page-script elements at end of head content
2024-12-17 12:31:40 -05:00
d65efed032 render page-script elements at end of head content 2024-12-17 12:31:26 -05:00
c6896ea936 Merge pull request #4920 from sbwalker/dev
fix page-script to support type attribute on inline scripts
2024-12-17 09:13:42 -05:00
b7a41bddec fix page-script to support type attribute on inline scripts 2024-12-17 09:13:26 -05:00
6fd80c3737 Merge pull request #4919 from sbwalker/dev
page-script improvements
2024-12-17 08:34:55 -05:00
0aa690b3b1 page-script improvements 2024-12-17 08:34:39 -05:00
6d5bcfc6ed Implement Dynamic ProjectName Parameter Across Build Process
This pull request introduces a dynamic ProjectName parameter across our build process, enhancing flexibility and reducing hardcoding in our module and theme development workflow. The changes affect the project file, NuSpec file, command scripts.
2024-12-17 10:35:14 +01:00
b60de69fa5 Merge pull request #4917 from sbwalker/dev
improvements to page-script
2024-12-16 12:44:23 -05:00
d991b57d08 improvements to page-script 2024-12-16 12:44:07 -05:00
1133d7fcba User Profile Update: Utilizing User Settings Object
This pull request updates the User Profile implementation to utilize the existing User Settings object on the user object. While the current implementation is functional, this change offers several benefits:
Improved code consistency
Better guidance for developers accessing User Settings
Alignment with the framework's best practices
2024-12-14 11:09:54 +01:00
6fbf0383bb Merge pull request #4911 from leigh-pointer/FixGlow
This is a cosmetic fix to the Oqtane Glow image
2024-12-13 16:46:49 -05:00
0296230219 Merge pull request #4913 from sbwalker/dev
page-script enhancements
2024-12-13 16:46:23 -05:00
dedfbba27a page-script enhancements 2024-12-13 16:46:08 -05:00
dc5441da07 This is a cosmetic fix to the Oqtane Glow image
The glow on the original is cropped at the left by a few pixcels.  This update fixes that and sizes the image to a 600 x 150
2024-12-13 11:45:13 +01:00
585648b7f3 Merge pull request #4907 from leigh-pointer/ProfileMaxLength
FIX for #4906 Profile Field does not allow max length
2024-12-10 09:12:52 -05:00
cd0ee1c26d FIX for #4906 Profile Field does not allow max length
This update applies the maxlength attribute fix to all input and textarea elements. The maxlength attribute will only be added if p.MaxLength is greater than 0, allowing unlimited characters when it's 0 or less.
2024-12-10 09:25:01 +01:00
d7a7be5af4 Merge pull request #4904 from sbwalker/dev
add sync events for user login/logout
2024-12-09 10:55:55 -05:00
13e4267c11 add sync events for user login/logout 2024-12-09 10:55:40 -05:00
15bc47e3e8 Merge pull request #4898 from leigh-pointer/TemplateParam
Implement Dynamic TargetFramework in Debug Scripts #4897
2024-12-09 07:36:00 -05:00
1a4380dcd7 Variable update 2024-12-07 15:02:27 +01:00
5ace34b5cd Add the $TargetFramework macro to the Release Builds
Add the $TargetFramework macro to the Release Builds
2024-12-06 13:37:37 +01:00
f010c0f1fa Implement Dynamic TargetFramework in Debug Scripts #4897
This PR updates our debug scripts (both .cmd and .sh) to dynamically use the current TargetFramework passed from the build process. This change improves flexibility and future-proofs our build process for different .NET versions.
2024-12-05 12:43:38 +01:00
2c721ad5dd Merge pull request #4895 from tvatavuk/enh-4883-control-panel
Add ShowEditMode parameter to ControlPanel to allow hiding the Edit Mode toggle button
2024-12-04 08:25:17 -05:00
8a7c2ce2c2 Merge pull request #4894 from W6HBR/dev
Fix #4885 - Pass userid as int to GetUser for JWT authentication
2024-12-04 08:24:27 -05:00
b2a7b813de Remove redundant IServiceProvider injection 2024-12-04 09:39:02 +01:00
e85cf04b99 Fix #4883: Add ShowEditMode parameter to ControlPanel to allow hiding the Edit Mode toggle button 2024-12-04 09:37:21 +01:00
ab6fa48172 Fix #4885 - Pass userid as int to GetUser for JWT authentication 2024-12-03 10:34:44 -08:00
c81905882f Merge pull request #4881 from sbwalker/dev
improve security of UserRole API
2024-11-27 14:59:41 -05:00
f0d31c1114 improve security of UserRole API 2024-11-27 14:59:25 -05:00
497b255216 Merge pull request #4880 from sbwalker/dev
User Settings should only be accessible to individual users or administrators
2024-11-27 13:16:04 -05:00
d96286d771 User Settings should only be accessible to individual users or administrators 2024-11-27 13:15:43 -05:00
2441647d75 Merge pull request #4879 from sbwalker/dev
update EFCore.NamingConventions to .NET 9 package version
2024-11-27 13:06:53 -05:00
77b780d631 update EFCore.NamingConventions to .NET 9 package version 2024-11-27 13:06:37 -05:00
cdd03bf3d4 Merge pull request #4878 from sbwalker/dev
User Settings should only be accessible to individual users or administrators
2024-11-27 13:04:27 -05:00
e786c35f7d User Settings should only be accessible to individual users or administrators 2024-11-27 13:04:06 -05:00
e83399acb1 Merge pull request #4876 from sbwalker/dev
prevent notifications from being accessed by other users
2024-11-26 14:30:55 -05:00
ffea9e3210 prevent notifications from being accessed by other users 2024-11-26 14:30:41 -05:00
f71a3a1ce3 Merge pull request #4875 from oqtane/revert-4828-TabChange
Revert "Fix for Tabpanel is not updating the UI. #4778"
2024-11-26 13:36:18 -05:00
a5ccc23604 Revert "Fix for Tabpanel is not updating the UI. #4778" 2024-11-26 13:36:05 -05:00
1ed4c8a094 Merge pull request #4874 from oqtane/revert-4871-HTMLTabError
Revert "Rework for Tabstrip regression issue"
2024-11-26 13:35:37 -05:00
4a74549c1b Revert "Rework for Tabstrip regression issue" 2024-11-26 13:35:21 -05:00
a499cfb98f Merge pull request #4871 from leigh-pointer/HTMLTabError
Rework for Tabstrip regression issue
2024-11-26 11:27:52 -05:00
01038c8296 Merge pull request #4873 from sbwalker/dev
include SECURITY.md
2024-11-26 11:25:35 -05:00
7407f79b3d include SECURITY.md 2024-11-26 11:25:23 -05:00
a845dd1976 Rework for Tabstrip regression issue
Fix for Tabpanel is not updating the UI. #4778 #4828
2024-11-26 15:39:51 +01:00
9d7549da70 Reverted TabStrip and Panel 2024-11-26 10:33:18 +01:00
f5cc61384f Merge pull request #4870 from sbwalker/dev
reference Quill CSS theme using BaseUrl so that it works in .NET MAUI as well as web
2024-11-25 14:20:15 -05:00
844778d36a reference Quill CSS theme using BaseUrl so that it works in .NET MAUI as well as web 2024-11-25 14:19:58 -05:00
871b0a274e Merge pull request #4869 from sbwalker/dev
improve message grammar
2024-11-25 13:48:41 -05:00
737740a3ca improve message grammar 2024-11-25 13:48:28 -05:00
ae8d600600 Update README.md 2024-11-25 09:11:12 -05:00
2f1691bfb0 Update README.md 2024-11-25 09:10:20 -05:00
a3d25f91c8 Update README.md 2024-11-25 09:09:52 -05:00
ff84b50817 Update README.md 2024-11-25 09:09:13 -05:00
0be8242284 Merge pull request #4862 from leigh-pointer/SettingsSetTabOnSave
Updated the Module Settings to use the new ActiveTab parameter
2024-11-25 08:39:45 -05:00
e25a6259ea Merge pull request #4861 from zyhfish/task/fix-4841
Fix #4841: force 2FA validation when it's required in site level.
2024-11-25 08:39:26 -05:00
1578f82efb Updated the Module Settings to use the new ActiveTab parameter 2024-11-23 11:42:22 +01:00
Ben
b5f75f0c5e Fix #4841: force 2FA validation when it's required in site level. 2024-11-23 13:04:27 +08:00
601caab3b6 Merge pull request #4860 from sbwalker/dev
fix #4760 - display update confirmation message in Site Settings
2024-11-22 16:34:46 -05:00
6d3092f440 fix #4760 - display update confirmation message in Site Settings 2024-11-22 16:34:35 -05:00
ef27937c7a Merge pull request #4785 from thabaum/refactored-heading-ifelse
Fixes #4784: Refactor TabPanel Heading Assignment Logic
2024-11-22 15:34:51 -05:00
f4a7b79c4f Merge pull request #4828 from leigh-pointer/TabChange
Fix for Tabpanel is not updating the UI. #4778
2024-11-22 15:30:51 -05:00
2531776a48 Merge pull request #4859 from sbwalker/dev
prepare for 6.0.1
2024-11-22 12:29:56 -05:00
ced80419aa prepare for 6.0.1 2024-11-22 12:29:44 -05:00
ad2816f4e8 Merge pull request #4858 from sbwalker/dev
fix #4848 - remove assemblies from /bin which have been moved to /bin/refs in .NET 9
2024-11-22 12:14:04 -05:00
3528b8c674 fix #4848 - remove assemblies from /bin which have been moved to /bin/refs in .NET 9 2024-11-22 12:13:45 -05:00
80c83c626d Merge pull request #4853 from leigh-pointer/PagerAlignment
Fix for #4852 align the Page numbers container
2024-11-22 11:56:12 -05:00
6a355f2aea Merge pull request #4857 from sbwalker/dev
fix #4855 - dropping required column causes issue on SQLite
2024-11-22 11:55:56 -05:00
7d94e4a53a fix #4855 - dropping required column causes issue on SQLite 2024-11-22 11:55:43 -05:00
823c04742e Merge pull request #4854 from sbwalker/dev
resolve .NET version issue in nuspec files
2024-11-21 10:54:06 -05:00
043fb1abd1 resolve .NET version issue in nuspec files 2024-11-21 10:53:52 -05:00
f01e85b690 Fix for #4852 align the Page numbers container 2024-11-21 16:05:32 +01:00
7eb1298847 Merge pull request #4847 from sbwalker/dev
do not include Oqtane.Server.staticwebassets.endpoints.json in release packages
2024-11-19 13:50:05 -05:00
a5480c9a96 do not include Oqtane.Server.staticwebassets.endpoints.json in release packages 2024-11-19 13:49:45 -05:00
f948600e86 Merge pull request #4845 from sbwalker/dev
fix 2 factor authentication email
2024-11-18 15:04:01 -05:00
420182b9bf fix 2 factor authentication email 2024-11-18 15:03:48 -05:00
8c430ce1a6 Merge pull request #4837 from Trifoia/4803-Add-a-CONTRIBUTING.md
4803 add a contributing.md
2024-11-15 15:02:28 -05:00
d3717dbe19 Remove DefaultDBType value and InstallationId from appsettings.json
The commit removes the value for DefaultDBType and InstallationId from the appsettings.json file.
2024-11-15 10:31:49 -08:00
caa83d769f Create CONTRIBUTING.md 2024-11-15 10:27:53 -08:00
365f87828f Merge remote-tracking branch 'oqtane/dev' into dev 2024-11-15 09:52:50 -08:00
f780887866 Update README.md 2024-11-14 15:46:26 -05:00
43627d4bb8 Merge pull request #4832 from oqtane/master
6.0.0 release
2024-11-14 15:40:38 -05:00
5d7b276cd1 Merge pull request #4831 from oqtane/dev
6.0.0 release
2024-11-14 15:40:17 -05:00
23597eb997 Merge pull request #4827 from leigh-pointer/Search-4824
Fix: for Disabling search does not hide search icon #4824
2024-11-14 07:54:52 -05:00
b6948367f8 Merge pull request #4826 from leigh-pointer/swash
Swashbuckle.AspNetCore updated to 7.0
2024-11-14 07:52:49 -05:00
db6dd5abee Fix for TabPanel is not updating the UI. #4778
Modified that TabStrip and TabPane, now when the ActiveTab is changed the TabPanel is selected
2024-11-14 10:35:15 +01:00
702eb9e466 Revert "Fix for Page Management tab panel is not updating the UI. #4778"
This reverts commit 3c99006226.
2024-11-14 10:33:10 +01:00
3c99006226 Fix for Page Management tab panel is not updating the UI. #4778 2024-11-14 10:31:53 +01:00
aaaf5683a5 Fix: "Search_Enabled" was being saved as Private so unauthorized users can not access this value. 2024-11-14 09:50:05 +01:00
92aa2236c0 Swashbuckle.AspNetCore updated to 7.0 2024-11-14 09:16:55 +01:00
d2592f72d6 Merge pull request #4825 from sbwalker/dev
modifications to get .NET MAUI working on .NET 9 official release
2024-11-13 20:37:24 -05:00
27120d6cc9 modifications to get .NET MAUI working on .NET 9 official release 2024-11-13 20:37:10 -05:00
a2669d35c3 Merge pull request #4823 from sbwalker/dev
exclude wwwroot/_content from official release build
2024-11-13 14:14:47 -05:00
574164081b exclude wwwroot/_content from official release build 2024-11-13 14:14:35 -05:00
00c2f8dcd8 Merge pull request #4822 from sbwalker/dev
adjust gitignore to exclude wwwroot/_content subfolders
2024-11-13 13:52:08 -05:00
0202bf60e5 adjust gitignore to exclude wwwroot/_content subfolders 2024-11-13 13:51:54 -05:00
16436a171b Merge pull request #4821 from zyhfish/task/fix-build-error
add reference to Microsoft.EntityFrameworkCore package.
2024-11-13 10:10:19 -05:00
Ben
4cf4e0eabd add reference to Microsoft.EntityFrameworkCore package. 2024-11-13 23:06:43 +08:00
5edb98dfb4 Merge pull request #4818 from sbwalker/dev
update PostgreSQL provider to official .NET 9 release
2024-11-12 15:50:27 -05:00
899bf22e15 update PostgreSQL provider to official .NET 9 release 2024-11-12 15:50:13 -05:00
9a33167a6c Merge pull request #4817 from sbwalker/dev
Update to official .NET 9 release
2024-11-12 15:43:42 -05:00
2dc068aa21 upgrade to official .NET 9 release 2024-11-12 15:42:57 -05:00
0f2aa4d2e1 update to official .NET 9 release 2024-11-12 15:40:54 -05:00
a699f5c7bc Merge pull request #4815 from mdmontesinos/dev
Fix: Accesibility issue for Search Button
2024-11-12 15:08:23 -05:00
ab807de3c0 Fix: Accesibility issue for Search Button
The search button in Search component does not have the aria-label.
2024-11-12 17:15:56 +01:00
68514bcb36 Merge pull request #4813 from sbwalker/dev
use HttpClient rather than IHttpClientFactory as IHttpClientFactory does not pass cookies in .NET MAUI
2024-11-11 08:15:14 -05:00
422bf8da59 use HttpClient rather than IHttpClientFactory as IHttpClientFactory does not pass cookies in .NET MAUI 2024-11-11 08:14:53 -05:00
de92dc93dd Merge pull request #4811 from sbwalker/dev
resolved issue when setting initial culture cookie
2024-11-08 15:41:36 -05:00
5a91b143b6 resolved issue when setting initial culture cookie 2024-11-08 15:41:24 -05:00
c745e85706 Merge pull request #4810 from sbwalker/dev
make indexing of Files opt-in rather than opt-out
2024-11-08 15:16:45 -05:00
0f698e0c50 make indexing of Files opt-in rather than opt-out 2024-11-08 15:16:32 -05:00
cd16d77bf0 Merge pull request #4809 from sbwalker/dev
Added defensive logic to File Indexer for scenarios where file does not exist on disk. Added ability to reset the search index prior to reindexing.
2024-11-07 17:05:48 -05:00
fdbdd0ef4c Added defensive logic to File Indexer for scenarios where file does not exist on disk. Added ability to reset the search index prior to reindexing. 2024-11-07 17:05:28 -05:00
71485f4a82 Merge pull request #4808 from sbwalker/dev
fix compilation warning
2024-11-07 15:45:47 -05:00
013056a6e5 fix compilation warning 2024-11-07 15:45:34 -05:00
263498fbdc Merge pull request #4807 from sbwalker/dev
remove icrosoft.AspNetCore.Localization from .NET MAUI project
2024-11-07 12:38:31 -05:00
f46ac2c007 remove icrosoft.AspNetCore.Localization from .NET MAUI project 2024-11-07 12:38:16 -05:00
c23841b6db Merge pull request #4806 from sbwalker/dev
default Description to Module Name if not specified in Module Creator
2024-11-07 11:53:15 -05:00
18b1b5fca5 default Description to Module Name if not specified in Module Creator 2024-11-07 11:52:53 -05:00
6707ac2697 Merge pull request #4802 from sbwalker/dev
remove custom JavaScript reconnection script for SignalR
2024-11-05 11:30:32 -05:00
d85a2fc8ce remove custom JavaScript reconnection script for SignalR 2024-11-05 11:30:18 -05:00
a8997e8f17 Merge pull request #4800 from sbwalker/dev
fix #4795 - ensure deterministic ordering of file parts when merging files after upload (credit @HQuast)
2024-11-04 15:29:16 -05:00
c8a22d9537 fix #4795 - ensure deterministic ordering of file parts when merging files after upload (credit @HQuast) 2024-11-04 15:28:59 -05:00
910669f786 Merge pull request #4793 from thabaum/patch-12
Fixes #4792: Update Oqtane.Server.csproj Package Dependencies
2024-11-01 15:40:14 -04:00
89312c6796 Update Oqtane.Server.csproj Package Dependencies 2024-10-30 18:43:42 -07:00
a6aa96fdb0 Merge pull request #4786 from sbwalker/dev
fix #4770 - set a default value for PrincipalSchema to ensure backward compatibility
2024-10-24 17:08:42 -04:00
7deb0b06af fix #4770 - set a default value for PrincipalSchema to ensure backward compatibility 2024-10-24 17:08:25 -04:00
784f3771b3 Remove Blank Page Specific Error Message 2024-10-24 13:22:08 -07:00
80316824f7 Remove Blank Page Specific Error Message 2024-10-24 13:21:40 -07:00
cbaebb7b7c Remove Blank Page Specific Error Message 2024-10-24 13:21:15 -07:00
97d3764b6e Remove Blank Page Specific Error Message 2024-10-24 13:20:52 -07:00
002f8117cb Merge pull request #4783 from sbwalker/dev
get language using CookieRequestCultureProvider
2024-10-24 15:48:28 -04:00
0dfdb12431 get language using CookieRequestCultureProvider 2024-10-24 15:48:14 -04:00
d77e898929 Refactor TabPanel Heading Assignment Logic
- Simplified the logic for setting the Heading property in the TabPanel component.
- Replaced the if-else statement with a ternary operator for improved readability and maintainability.
- Ensured that the functionality remains unchanged and verified correct assignment of headings.
2024-10-24 12:43:20 -07:00
4c937be884 Clarify Page Name Required Message 2024-10-24 12:38:51 -07:00
c25cce4398 Clarify Page Name Required Message 2024-10-24 12:38:16 -07:00
58c422285a Adds Message.Required.PageName 2024-10-24 12:28:17 -07:00
f2f22f35e8 Adds Message.Required.PageName 2024-10-24 12:26:36 -07:00
15867a7807 Adds await ScrollToPageTop(); to error messages + Page Name Error Message 2024-10-24 12:23:29 -07:00
22e3161a9b Merge pull request #4780 from sbwalker/dev
remove Microsoft.AspNetCore.Localization from default module template
2024-10-24 15:20:20 -04:00
b0c8203b24 remove Microsoft.AspNetCore.Localization from default module template 2024-10-24 15:20:07 -04:00
e2c404d8bb Adds await ScrollToPageTop(); to error messages + Page Name Error Message
- Adds await ScrollToPageTop(); to error messages
- Adds Blank Page Name Error Message
2024-10-24 12:18:30 -07:00
5ee1731c92 Merge pull request #4777 from thabaum/update-html-agility-pack-1.11.69
Fixes #4776: Updates HtmlAgilityPack to 1.11.69
2024-10-24 15:12:17 -04:00
06e8d3b660 Merge pull request #4779 from sbwalker/dev
remove Microsoft.AspNetCore.Http
2024-10-24 15:11:07 -04:00
f09709aedb remove Microsoft.AspNetCore.Http 2024-10-24 15:10:52 -04:00
598d5decac Update HtmlAgilityPack to 1.11.69 2024-10-24 10:18:24 -07:00
7832a6053e Merge pull request #4775 from sbwalker/dev
remove some dependencies on Microsoft.AspNetCore.Http
2024-10-24 13:16:21 -04:00
588748230e remove some dependencies on Microsoft.AspNetCore.Http 2024-10-24 13:16:08 -04:00
8668165c72 Merge pull request #4774 from sbwalker/dev
remove Microsoft.AspNetCore.Localization
2024-10-24 12:25:04 -04:00
a967332f89 remove Microsoft.AspNetCore.Localization 2024-10-24 12:24:46 -04:00
6719d242bd Merge pull request #4756 from zyhfish/task/fix-4752
Fix #4752: validate the username and email.
2024-10-24 09:53:24 -04:00
Ben
3565185808 update the error message. 2024-10-24 20:13:43 +08:00
Ben
ce51262197 update the code to use simple validation. 2024-10-24 20:04:18 +08:00
992a786c2b Merge pull request #4763 from thabaum/ScrollTo-interop-modal
Fixes #4762: Adds logic ScrollTo interop.js method detecting if method is executed inside a modal
2024-10-22 16:28:45 -04:00
038df95aa0 Merge pull request #4759 from thabaum/scroll-to-top-user-settings
Scroll to top after saving settings - Fixes #4758
2024-10-22 16:28:33 -04:00
4ebd660de2 Merge pull request #4766 from sbwalker/dev
resolve compiler warning in .NET MAUI
2024-10-21 15:42:08 -04:00
a9ea41a488 resolve compiler warning in .NET MAUI 2024-10-21 15:41:57 -04:00
196594b490 Merge pull request #4765 from sbwalker/dev
update MAUI project to .NET 9 RC2
2024-10-21 15:34:34 -04:00
1516d5af10 update MAUI project to .NET 9 RC2 2024-10-21 15:34:22 -04:00
ffcd1595a9 Merge pull request #4764 from sbwalker/dev
update Updater to .NET 9
2024-10-21 15:25:27 -04:00
42e5c6e111 update Updater to .NET 9 2024-10-21 15:25:14 -04:00
8a9651dc50 Adds logic for .modal class ScrollTo function 2024-10-21 12:22:01 -07:00
4be2f4f2d9 Update README.md 2024-10-21 15:21:29 -04:00
369bf7a235 Adds logic for .modal class ScrollTo function
fixes #4762
2024-10-21 12:20:24 -07:00
136545b404 Merge pull request #4761 from sbwalker/dev
changes to migrate Oqtane to .NET 9 and version 6.0.0
2024-10-21 14:51:38 -04:00
73ea17ae0f changes to migrate Oqtane to .NET 9 and version 6.0.0 2024-10-21 14:51:20 -04:00
23010acef4 Scroll to top after saving settings - Fixes #4758 2024-10-21 10:36:12 -07:00
Ben
4f74962ce2 Fix #4752: validate the username and email. 2024-10-21 23:11:57 +08:00
7f978c7845 Update README.md 2024-10-17 13:52:21 -04:00
731fd46ea2 Merge pull request #4747 from oqtane/master
5.2.4 release
2024-10-17 13:46:40 -04:00
859759d691 Merge pull request #4746 from oqtane/dev
5.2.4 release
2024-10-17 13:46:22 -04:00
5e9567158f Merge pull request #4744 from sbwalker/dev
add additional external login providers
2024-10-16 08:35:14 -04:00
51d244f3aa add additional external login providers 2024-10-16 08:35:01 -04:00
4c5a07edd5 Merge pull request #4743 from sbwalker/dev
add missing localization keys
2024-10-16 07:52:49 -04:00
8113a754a1 add missing localization keys 2024-10-16 07:52:36 -04:00
3cd40c6195 Merge pull request #4742 from sbwalker/dev
fix sorting of Site.Languages property
2024-10-15 16:46:16 -04:00
56cfb2ce06 fix sorting of Site.Languages property 2024-10-15 16:46:05 -04:00
72087823ac Merge pull request #4741 from sbwalker/dev
fix #4733 - remove Name column from Language table and populate value dynamically
2024-10-15 16:44:44 -04:00
bcf7866fe2 fix #4733 - remove Name column from Language table and populate value dynamically 2024-10-15 15:58:17 -04:00
b64772e484 Merge pull request #4739 from thabaum/add-discord-community
Fixes #4738 - Add Discord community button to README.md
2024-10-15 15:26:32 -04:00
088d665942 Update Discord Community Link For Consistency 2024-10-15 10:27:59 -07:00
7d6c10befb Add Discord community button to README.md
- Added a button for joining the Oqtane Discord server
- Included a brief description encouraging community engagement
2024-10-15 10:17:01 -07:00
f88e3d04b8 Merge pull request #4736 from thabaum/mysql.data-9.1.0
Fixes #4735 - Update MySQL.Data to 9.1.0
2024-10-15 12:06:50 -04:00
f57676a22b Update MySQL.Data to 9.1.0 2024-10-15 08:15:52 -07:00
8618cb62e4 Merge pull request #4732 from sbwalker/dev
fix #4711 - full page refresh required to affect language changes
2024-10-15 08:32:08 -04:00
c31c88ed1f fix #4711 - full page refresh required to affect language changes 2024-10-15 08:31:54 -04:00
6022acd21f Merge pull request #4731 from sbwalker/dev
fix #4716 - sort recycle bin items by DeletedOn date descending
2024-10-15 07:56:07 -04:00
b3071b9272 fix #4716 - sort recycle bin items by DeletedOn date descending 2024-10-15 07:55:54 -04:00
ec6a6d6653 Merge pull request #4729 from sbwalker/dev
localize names of languages based on user's UI culture
2024-10-14 17:18:09 -04:00
52f552b4de localize names of languages based on user's UI culture 2024-10-14 17:17:54 -04:00
2643d3396b Merge pull request #4728 from sbwalker/dev
set HttpOnly to false for Localization cookie in static rendering
2024-10-14 16:49:27 -04:00
62d59a09cf set HttpOnly to false for Localization cookie in static rendering 2024-10-14 16:49:14 -04:00
a68ff8a4f0 Merge pull request #4727 from sbwalker/dev
When displaying Database Type use SQL Server rather than LocalDB to avoid confusion
2024-10-14 16:21:25 -04:00
93d4bfcd7a When displaying Database Type use SQL Server rather than LocalDB to avoid confusion 2024-10-14 16:21:03 -04:00
5fb80c1a7b Merge pull request #4726 from sbwalker/dev
fix #4722 - support PrincipalSchema when creating foreign keys (credit @Hypnodude)
2024-10-14 15:36:54 -04:00
04b38444ce fix #4722 - support PrincipalSchema when creating foreign keys (credit @Hypnodude) 2024-10-14 15:36:32 -04:00
ca3df02002 Merge pull request #4723 from mdmontesinos/dev
Image Resizing and Format via QueryString in Files Page (enhances #4692)
2024-10-14 15:20:37 -04:00
d952c33fab Merge pull request #4725 from sbwalker/dev
fix #4714 as well as breaking change in #4712
2024-10-14 15:05:59 -04:00
93bc1cd5af fix #4714 as well as breaking change in #4712 2024-10-14 15:05:46 -04:00
0e5b370ee8 Merge pull request #4712 from thabaum/language-switcher-cookie
Fix #4710 - Adds language switcher component cookie set options for secure, httpOnly, sameSite + interop.cs/interop.js methods samesite and secure options
2024-10-14 14:41:18 -04:00
f4fd4e28c9 Merge pull request #4724 from sbwalker/dev
update MAUI project to .NET 8.0.10
2024-10-14 13:12:09 -04:00
ec8433eb45 update MAUI project to .NET 8.0.10 2024-10-14 13:11:55 -04:00
0d4a40e9bb Merge pull request #4715 from leigh-pointer/CompUpdate-8.0.10
Updated Microsoft Components for 8.0.8 to 8.0.10
2024-10-14 13:04:54 -04:00
c3668f4179 Merge pull request #4708 from thabaum/patch-10
fix typo in startup.cs
2024-10-14 12:48:38 -04:00
3adb7ecb1c Enhances image manipulation with format (webp encoder, defaults to png)
- computes etag with all manipulation parameters
2024-10-13 17:20:18 +02:00
aa5b84a214 Implements Image Manipulation in Files Page via QueryString
- Extracts the image creation into a service
- Refactors Files Page GET action for better readability and cyclomatic complexity
2024-10-13 12:38:43 +02:00
3d83fccbf1 remove appsettings 2024-10-09 15:07:57 +02:00
4c4255be6b Updated Template files with new component version 8.0.10 2024-10-09 14:42:07 +02:00
ed6054b082 Updated Microsoft Components for 8.0.8 to 8.0.10
Tested on upgrade and new Oqtane instance creation.
2024-10-09 14:35:27 +02:00
f60f7a4dc1 Remove httpOnly setting from setCookie 2024-10-05 14:17:20 -07:00
998dc95cb2 Removed extra attribute for interop.SetCookie 2024-10-05 14:08:16 -07:00
12f5d7b846 Remove extra attribute for SetCookie 2024-10-05 14:06:35 -07:00
906ae0a43e Remove extra attribute for SetCookie 2024-10-05 14:06:18 -07:00
485b774876 Remove httpOnly cooking attribute from SetCookie 2024-10-05 14:03:20 -07:00
3121cf5b75 Remove unnecessary httpOnly setCookie option 2024-10-05 14:00:18 -07:00
ce7570dae2 Remove Unnecessary httpOnly setting setCookie Option 2024-10-05 13:58:55 -07:00
b5ea0dfbc7 Update Cleanup "setCookie" function notes options: secure, httpOnly, Samesite 2024-10-05 13:57:36 -07:00
dd0f8f4772 Update SetCookie function to include secure, httpOnly and sameSite 2024-10-05 13:55:35 -07:00
9d0ab34274 Update 'SetCookie" option settings "secure, httpOnly, sameSite" 2024-10-05 13:28:33 -07:00
e6038be6f7 Update SetCookie Option Settings Secure, HttpOnly, SameSite 2024-10-05 13:27:14 -07:00
bd2153a0ed Update cookie options to set SameSite, HttpOnly, Secure settings 2024-10-05 13:23:09 -07:00
e526deac20 Update Cookie Settings Secure, httpOnly, sameSite 2024-10-05 13:19:52 -07:00
b65f165dcf Update adds SameSite, Secure and httpOnly SetCookie Settings 2024-10-05 13:17:31 -07:00
f9fbe5adc2 Update NavigateTo() to use "true" instead of "forceLoad: true" 2024-10-05 12:11:52 -07:00
d1e73571a1 fix typo 2024-10-05 11:12:01 -07:00
1047058676 Merge pull request #4705 from maurocavallin/dev
Hard deletion of page more robust use of entity framework contexts
2024-10-04 17:14:00 -04:00
29a1e77da8 Hard deletion of page more robust use of contexts (fixes issue: presence of stale records of deleted page on db). 2024-10-04 22:46:40 +02:00
290547e482 Merge pull request #4702 from sbwalker/dev
add defensive logic if ModuleState is null  in ModuleMessage
2024-10-02 16:53:46 -04:00
3df45ca20f add defensive logic if ModuleState is null in ModuleMessage 2024-10-02 16:53:36 -04:00
cc06258484 Merge pull request #4701 from sbwalker/dev
updated version to 5.2.4
2024-10-02 16:39:45 -04:00
2c262d0655 updated version to 5.2.4 2024-10-02 16:39:31 -04:00
1875e1e158 Merge pull request #4696 from sbwalker/dev
fix #4695 - null reference exception deleting a setting which does not exist
2024-10-02 08:30:58 -04:00
1c95967b31 fix #4695 - null reference exception deleting a setting which does not exist 2024-10-02 08:30:34 -04:00
2ae98929de Merge pull request #4689 from thabaum/Update-Dependencies-and-Prepare-Release-5.2.4
Fixes #4688 - Update dependencies and prepare release 5.2.4
2024-10-01 11:21:35 -04:00
6a1dd38cbb Merge pull request #4691 from zyhfish/task/fix-4690
Fix #4690: prevent invalid parsing.
2024-10-01 11:20:01 -04:00
Ben
c458a77d27 Fix #4690: prevent invalid parsing. 2024-10-01 22:13:32 +08:00
352c23f389 Prepare Release 5.2.4 2024-10-01 06:15:46 -07:00
6c5a1dc2e1 Prepare Release 5.2.4 2024-10-01 06:14:57 -07:00
004ff1e91d Update Dependencies and Prepare Release 5.2.4 2024-10-01 06:14:07 -07:00
f7de4c567b Prepare Release 5.2.4 2024-10-01 06:12:07 -07:00
b2ad1010ac Prepare Release 5.2.4 2024-10-01 06:11:36 -07:00
660e164ff8 Prepare Release 5.2.4 2024-10-01 06:11:04 -07:00
eb6dc80b50 Prepare Release 5.2.4 - removed whitespace 2024-10-01 06:10:21 -07:00
a9882cc96a Update Oqtane.Shared.nuspec 2024-10-01 06:09:35 -07:00
fb5a2ce178 Prepare Release 5.2.4 2024-10-01 06:09:12 -07:00
d441b31dc7 Prepare Release 5.2.4 2024-10-01 06:08:46 -07:00
d4239fe7e0 Prepare Release 5.2.4 2024-10-01 06:07:55 -07:00
6a98999105 Prepare Release 5.2.4 2024-10-01 06:06:03 -07:00
5caa1fe7d4 Prepare Release 5.2.4 2024-10-01 06:05:07 -07:00
ef33bdb65e Prepare Release 5.2.4 2024-10-01 06:04:11 -07:00
14a463382b Prepare Release 5.2.4 2024-10-01 06:03:20 -07:00
1ad79874c8 Update Dependencies and Prepare Release 5.2.4 2024-10-01 06:02:40 -07:00
1a61a58d28 Prepare Release 5.2.4 2024-10-01 06:00:20 -07:00
3e3c973679 Prepare Release 5.2.4 2024-10-01 05:59:47 -07:00
9dede84d20 Update Dependencies and Prepare Release 5.2.4 2024-10-01 05:57:17 -07:00
e78b11cf62 Merge pull request #4687 from sbwalker/dev
add some clarity to the database fields help text
2024-09-30 13:32:08 -04:00
341ca5a330 add some clarity to the database fields help text 2024-09-30 13:31:57 -04:00
e5d8c02def Merge pull request #4686 from sbwalker/dev
add validation of recipient email address to Notification job
2024-09-30 11:27:59 -04:00
947aa08c42 add validation of recipient email address to Notification job 2024-09-30 11:27:47 -04:00
9a04d436bd Merge pull request #4683 from sbwalker/dev
simplify configuration of external login providers
2024-09-27 16:21:23 -04:00
be0754f568 simplify configuration of external login providers 2024-09-27 16:21:06 -04:00
93c4bbc0d1 Merge pull request #4682 from sbwalker/dev
fix #4654 - show progress indicator during download
2024-09-27 12:01:07 -04:00
b98535810b fix #4654 - show progress indicator during download 2024-09-27 12:00:49 -04:00
393cf8da1f Merge pull request #4681 from sbwalker/dev
add disclaimer to System Update feature
2024-09-27 09:00:15 -04:00
ea2846973a add disclaimer to System Update feature 2024-09-27 09:00:04 -04:00
3398c1cbfe Merge pull request #4678 from sbwalker/dev
remove unnecessary using statement
2024-09-26 15:54:35 -04:00
39c79ea68e remove unnecessary using statement 2024-09-26 15:54:22 -04:00
66900f4a32 Merge pull request #4677 from sbwalker/dev
sign out the principal when it is rejected due to security stamp changes
2024-09-26 15:53:55 -04:00
df71dd14f7 sign out the principal when it is rejected due to security stamp changes 2024-09-26 15:53:14 -04:00
8113ca3069 Merge pull request #4676 from sbwalker/dev
fix #4657 - Cannot add new site to existing installation using separate database On IIS
2024-09-26 14:07:11 -04:00
d468e675c2 fix #4657 - Cannot add new site to existing installation using separate database On IIS 2024-09-26 14:06:51 -04:00
1e84cedf82 Merge pull request #4674 from sbwalker/dev
fix localization spelling mistake
2024-09-26 13:46:41 -04:00
7f4087e3de fix localization spelling mistake 2024-09-26 13:46:29 -04:00
facd3c8956 Merge pull request #4673 from sbwalker/dev
fix remote login issue which could occut if multiple users have the same email address
2024-09-26 13:38:30 -04:00
3e50deecb7 fix remote login issue which could occut if multiple users have the same email address 2024-09-26 13:37:39 -04:00
628c504f84 Merge pull request #4672 from sbwalker/dev
fix #4667 - installation issues when running on IIS
2024-09-26 13:33:31 -04:00
e1ada78c1f fix #4667 - installation issues when running on IIS 2024-09-26 13:33:16 -04:00
09fa1e365c Merge pull request #4670 from thabaum/remove-unnecessary-usings
Fixes #4669 - Remove unnecessary usings in IMultiDatabase.cs
2024-09-26 13:32:33 -04:00
28b6b03d06 Remove unnecessary usings 2024-09-25 15:13:06 -07:00
a4395b62ff Merge pull request #4668 from sbwalker/dev
fix #4666 - scroll position in enhanced navigation
2024-09-25 17:06:03 -04:00
4511acf273 fix #4666 - scroll position in enhanced navigation 2024-09-25 17:05:53 -04:00
fde53a2d83 Update README.md 2024-09-23 16:33:41 -04:00
f6cd04fdb8 Merge pull request #4662 from oqtane/master
Merge pull request #4661 from oqtane/dev
2024-09-23 16:26:39 -04:00
a5eede6c7a Merge pull request #4661 from oqtane/dev
5.2.3 release
2024-09-23 16:26:24 -04:00
2e83817c83 Merge pull request #4660 from sbwalker/dev
prepare for 5.2.3
2024-09-23 16:18:10 -04:00
82aea40ae4 prepare for 5.2.3 2024-09-23 16:17:55 -04:00
1b289eae24 Merge pull request #4659 from sbwalker/dev
use RoleName rather than RoleId for consistency
2024-09-23 16:08:02 -04:00
81420b2c88 use RoleName rather than RoleId for consistency 2024-09-23 16:07:49 -04:00
775731b745 Merge pull request #4657 from thabaum/patch-9
FIX #4655 - autocomplete="off" for SMTP Username/Password
2024-09-23 15:44:06 -04:00
489e7d4a67 Merge pull request #4658 from sbwalker/dev
fix RoleId missing from Permission Clone method
2024-09-23 15:38:51 -04:00
b6508764d8 fix RoleId missing from Permission Clone method 2024-09-23 15:38:35 -04:00
6dedd87305 autocomplete="off" for SMTP Username/Password 2024-09-23 12:19:49 -07:00
89fa29b310 Merge pull request #4653 from sbwalker/dev
improve scroll position script
2024-09-23 09:55:59 -04:00
be5df9c22a improve scroll position script 2024-09-23 09:55:44 -04:00
db17739716 Update README.md 2024-09-23 07:48:14 -04:00
1439362a5e Merge pull request #4651 from oqtane/master
5.2.2 Release
2024-09-23 07:39:21 -04:00
65c1b04772 Merge pull request #4650 from oqtane/dev
5.2.2 Release
2024-09-23 07:39:02 -04:00
83d30ebdc4 Merge pull request #4645 from sbwalker/dev
fix #4638 - add Logout Everywhere option to User Profile
2024-09-20 15:18:38 -04:00
b7928a5255 fix #4638 - add Logout Everywhere option to User Profile 2024-09-20 15:18:25 -04:00
a83ff9253d Merge pull request #4644 from sbwalker/dev
fix code formatting
2024-09-20 12:54:44 -04:00
8cdcdaf6d9 fix code formatting 2024-09-20 12:54:34 -04:00
d208edf153 Merge pull request #4643 from sbwalker/dev
fix #4641 - highlight default site theme in list of themes in page management
2024-09-20 12:28:06 -04:00
8ada4765b1 fix #4641 - highlight default site theme in list of themes in page management 2024-09-20 12:27:49 -04:00
9d3a808c24 Merge pull request #4642 from sbwalker/dev
fix #4826 - improve url handling
2024-09-20 12:09:16 -04:00
828eb80266 fix #4826 - improve url handling 2024-09-20 12:09:04 -04:00
0639f6c1d1 Merge pull request #4640 from sbwalker/dev
fix #4628 - preserve Url for all ModuleActions
2024-09-19 14:09:55 -04:00
49b971280f fix #4628 - preserve Url for all ModuleActions 2024-09-19 14:09:45 -04:00
3682a1010d Merge pull request #4637 from sbwalker/dev
synchronize interop.js with .NET MAUI
2024-09-19 12:14:36 -04:00
f8b58866dc synchronize interop.js with .NET MAUI 2024-09-19 12:14:24 -04:00
5d8d815d84 Merge pull request #4636 from zyhfish/task/4610-loadjs-issue
Fix #4610: wait for js loaded.
2024-09-19 12:10:55 -04:00
Ben
67743c7597 Fix #4610: wait for js loaded. 2024-09-19 23:34:59 +08:00
b33cc90447 Merge pull request #4635 from sbwalker/dev
use deep cloning to not muttate cache
2024-09-19 09:41:24 -04:00
78177f7890 use deep cloning to not muttate cache 2024-09-19 09:41:11 -04:00
3c417bfa99 Merge pull request #4633 from sbwalker/dev
fix trimming of site, page, and module settings
2024-09-18 18:32:04 -04:00
f2c8d80ff8 fix trimming of site, page, and module settings 2024-09-18 18:31:40 -04:00
8c1eb1e19f Merge pull request #4632 from sbwalker/dev
fix #4257 - load settings resources
2024-09-18 15:22:58 -04:00
eb7188e81b fix #4257 - load settings resources 2024-09-18 15:22:44 -04:00
f352fc5c67 Merge pull request #4631 from sbwalker/dev
on .NET MAUI provide message to user if Security Token has not been configured
2024-09-18 11:28:30 -04:00
ac313722f9 on .NET MAUI provide message to user if Security Token has not been configured 2024-09-18 11:28:11 -04:00
64c7f1962c Merge pull request #4630 from zyhfish/task/sync-maui-resources
sync changes to maui resources.
2024-09-18 10:46:34 -04:00
Ben
c83f994b21 sync changes to maui resources. 2024-09-18 22:44:14 +08:00
10f38a72f7 Merge pull request #4629 from sbwalker/dev
fix #4628 - preserve ReturnUrl when navigating to Settings component
2024-09-18 09:43:11 -04:00
da35434f58 fix #4628 - preserve ReturnUrl when navigating to Settings component 2024-09-18 09:42:56 -04:00
c79409e094 Merge pull request #4627 from sbwalker/dev
use FileLogger as fallback in LogManager when site cannot be determined
2024-09-18 07:38:20 -04:00
355ce00968 use FileLogger as fallback in LogManager when site cannot be determined 2024-09-18 07:37:52 -04:00
56c832f3ba Merge pull request #4626 from sbwalker/dev
fix logic to force authenticated user to provide email address so it works in static rendering
2024-09-17 17:29:30 -04:00
40abb2720e fix logic to force authenticated user to provide email address so it works in static rendering 2024-09-17 17:29:11 -04:00
9b6051afee Merge pull request #4625 from sbwalker/dev
update nuget.exe to latest and fix nuspec specification of readme
2024-09-17 15:19:57 -04:00
dcf6f26792 update nuget.exe to latest and fix nuspec specification of readme 2024-09-17 15:19:40 -04:00
85734c1146 Merge pull request #4624 from sbwalker/dev
remove unecessary using
2024-09-17 11:54:33 -04:00
c3fb8fcb6e remove unecessary using 2024-09-17 11:54:21 -04:00
013bbc1638 Merge pull request #4623 from sbwalker/dev
fix external login
2024-09-17 11:53:47 -04:00
b0669a3b60 fix external login 2024-09-17 11:53:34 -04:00
6f5da1ce7c Merge pull request #4622 from sbwalker/dev
allow external login to support SecurityStamp
2024-09-17 09:28:47 -04:00
3351732a2f allow external login to support SecurityStamp 2024-09-17 09:28:35 -04:00
d4d4034ecd Merge pull request #4621 from sbwalker/dev
remove unecessary usings
2024-09-17 09:07:57 -04:00
b45e2742c3 remove unecessary usings 2024-09-17 09:07:45 -04:00
42eba290e4 Merge pull request #4620 from sbwalker/dev
allow JwtMiddleware to support SecurityStamp
2024-09-17 09:07:14 -04:00
32d1e08b57 allow JwtMiddleware to support SecurityStamp 2024-09-17 09:06:49 -04:00
7b7d19da7c Merge pull request #4619 from sbwalker/dev
fix commented logic
2024-09-17 08:55:09 -04:00
f78e400918 fix commented logic 2024-09-17 08:54:52 -04:00
be4e9bf7e9 Merge pull request #4618 from sbwalker/dev
fix #4580 - add logout everywhere support using SecurityStamp
2024-09-17 08:45:41 -04:00
48f2079f88 fix #4580 - add logout everywhere support using SecurityStamp 2024-09-17 08:45:27 -04:00
36ad1ceef2 Merge pull request #4617 from sbwalker/dev
fix #4607 - site level scripts added twice in static rendering
2024-09-16 13:22:10 -04:00
1f2e2148d5 fix #4607 - scripts added twice 2024-09-16 13:21:43 -04:00
76f3d345f9 Merge pull request #4616 from sbwalker/dev
include SecurityStamp in User object
2024-09-16 13:03:32 -04:00
f2c854b53a include SecurityStamp in User object 2024-09-16 13:03:21 -04:00
e2d336d90b Merge pull request #4613 from sbwalker/dev
further modifications for #4604 - support for site name in logo component
2024-09-15 09:30:24 -04:00
c74065ff26 further modifications for #4604 - support for site name in logo component 2024-09-15 09:30:04 -04:00
b6d97dc5d5 Merge pull request #4612 from sbwalker/dev
fix #4606 - allow logo to show site name as fallback (credit @JanOlsmar)
2024-09-13 16:13:14 -04:00
1c1c26948a fix #4606 - allow logo to show site name as fallback (credit @JanOlsmar) 2024-09-13 16:13:01 -04:00
d954e3ffb7 Merge pull request #4608 from hishamco/toggle-edit-mode
Fix issue in toggle edit mode
2024-09-13 15:54:37 -04:00
d9759a95eb Merge pull request #4611 from sbwalker/dev
fix #4607 - Site HeadContent scripts being added twice
2024-09-13 15:19:31 -04:00
d196402dd0 fix #4607 - Site HeadContent scripts being added twice 2024-09-13 15:18:12 -04:00
0f2b5531de Merge pull request #4601 from hishamco/module-settings
Add null operator in ModuleState.ModuleDefinition
2024-09-13 14:13:40 -04:00
26e4398905 Address feedback 2024-09-13 21:12:18 +03:00
06995f22fe Merge pull request #4609 from sbwalker/dev
improve support for external login roles
2024-09-13 07:35:10 -04:00
caa2073d48 improve support for external login roles 2024-09-13 07:34:57 -04:00
d9466fe4bc Fix issue in toggle edit mode 2024-09-13 14:15:34 +03:00
72e623a3a7 Merge pull request #4606 from sbwalker/dev
fix #4598 - user experience improvements for file upload
2024-09-12 14:04:48 -04:00
69bc06685f fix #4598 - user experience improvements for file upload 2024-09-12 14:04:35 -04:00
bf175984f3 Merge remote-tracking branch 'origin/dev' into dev 2024-09-11 18:23:41 -07:00
4d4a7bfd0d Merge pull request #4605 from sbwalker/dev
fix #4600 - filter user settings in API layer
2024-09-11 17:21:24 -04:00
044cee30a5 fix #4600 - filter user settings in API layer 2024-09-11 17:21:12 -04:00
3c0c5aed60 Add null operator in ModuleState.ModuleDefinition 2024-09-11 02:09:02 +03:00
e194971727 Merge pull request #4597 from sbwalker/dev
fix #4503 - ensure all state is initialized before rendering
2024-09-09 09:17:40 -04:00
bbe85def23 fix #4503 - ensure all state is initialized before rendering 2024-09-09 09:17:27 -04:00
9c2d53f2ae Merge pull request #4596 from sbwalker/dev
fix #4575 - add support for DateOnly and TimeOnly columns in migrations
2024-09-08 11:43:50 -04:00
1cf36e2156 fix #4575 - add support for DateOnly and TimeOnly columns in migrations 2024-09-08 11:43:36 -04:00
ce96e309af Merge pull request #4594 from sbwalker/dev
reverting #4507 - permission grid
2024-09-06 11:57:38 -04:00
9ea7dc8b3c reverting #4507 2024-09-06 11:57:15 -04:00
282242efd2 Merge pull request #4593 from mdmontesinos/dev
Fix IconOnly not working
2024-09-06 10:47:45 -04:00
351ba22d64 Fix IconOnly not working 2024-09-06 16:35:44 +02:00
2916625747 Merge pull request #4588 from thabaum/patch-8
Update MySQL Project File Version - Prepare for 5.2.2
2024-09-05 10:32:54 -04:00
744dbeb7a3 Prepare for 5.2.2 2024-09-04 17:43:20 -07:00
fbb3c309ee Merge pull request #4583 from sbwalker/dev
prepare for 5.2.2
2024-09-02 12:09:24 -04:00
473c265bac prepare for 5.2.2 2024-09-02 12:09:06 -04:00
01b06c2c3c Merge pull request #4582 from sbwalker/dev
remove reference to HttpContext as it is not used
2024-09-02 11:08:38 -04:00
8b1f95c743 remove reference to HttpContext as it is not used 2024-09-02 11:08:25 -04:00
ff5dbec579 Merge pull request #4578 from sbwalker/dev
fix issue adding existing user to a new site
2024-08-29 17:53:27 -04:00
9620c5a98f fix issue adding existing user to a new site 2024-08-29 17:53:11 -04:00
7e849a2e95 Merge pull request #4577 from zyhfish/task/update-bootstrap-reference 2024-08-29 09:35:32 -04:00
Ben
229aed306e update bootstrap reference. 2024-08-29 19:41:27 +08:00
d718969cbd Merge pull request #4574 from zyhfish/task/display-upgrade-progress
display the upgrade progress.
2024-08-28 21:22:08 -04:00
8593f4c3a9 Merge pull request #4576 from sbwalker/dev
improve developer experience for Url helper methods
2024-08-28 21:21:57 -04:00
d4f71d5026 improve developer experience for Url helper methods 2024-08-28 21:21:41 -04:00
a683a5f206 Merge pull request #4573 from leigh-pointer/AddExisitng
Fix for Deleted Modules showing in AddExisting & CopyExisting dropdow…
2024-08-28 21:17:54 -04:00
Ben
7917cc3eb5 display the upgrade progress. 2024-08-28 21:48:40 +08:00
6cd7ca755e Fix for Deleted Modules showing in AddExisting & CopyExisting dropdown #4572 2024-08-28 10:57:42 +02:00
fb7dfdc800 Merge pull request #4571 from sbwalker/dev
provide better support for AllowTextInput on Search component
2024-08-27 12:16:50 -04:00
e096af320f provide better support for AllowTextInput on Search component 2024-08-27 12:16:36 -04:00
65bff8f511 Merge pull request #4570 from sbwalker/dev
allow progress indicator to be displayed in search results
2024-08-27 10:22:53 -04:00
ca19d8a842 allow progress indicator to be displayed in search results 2024-08-27 10:22:41 -04:00
cde08c64ce Update README.md 2024-08-26 17:00:07 -04:00
3d6d7b7cb9 Update README.md 2024-08-26 16:56:08 -04:00
a56ef6f398 Update README.md 2024-08-26 16:55:30 -04:00
5a38b6614d Update README.md 2024-08-26 16:54:45 -04:00
3d5c44e8aa Update README.md 2024-08-26 16:53:25 -04:00
46a68bd5e7 Update README.md 2024-08-26 16:51:53 -04:00
c77ded51a9 Merge pull request #4568 from sbwalker/dev
fix #4559 - prevednt Log fields from exceeding column length
2024-08-26 12:05:05 -04:00
59bd9fdc22 fix #4559 - prevednt Log fields from exceeding column length 2024-08-26 12:04:50 -04:00
b81941394c Merge pull request #4567 from sbwalker/dev
change parameter name to AllowTextInput for clarity
2024-08-26 10:47:29 -04:00
197d5ca1f2 change parameter name to AllowTextInput for clarity 2024-08-26 10:47:18 -04:00
97eb986fa6 Merge pull request #4566 from sbwalker/dev
fix Search theme control so that it checks if search is enabled for site, and include AllowInput parameter to control input textbox
2024-08-26 10:41:39 -04:00
aba3110e31 fix Search theme control so that it checks if search is enabled for site, and include AllowInput parameter to control input textbox 2024-08-26 10:41:22 -04:00
51c27be236 Merge pull request #4565 from sbwalker/dev
fix #4562 - module template issue caused by gitignore
2024-08-26 09:41:01 -04:00
592255284f fix #4562 - module template issue caused by gitignore 2024-08-26 09:38:10 -04:00
82fd41dd4c Merge pull request #4555 from sbwalker/dev
add readme.md to Oqtane nuget packages
2024-08-22 14:10:42 -04:00
4ae8df9652 add readme.md to Oqtane nuget packages 2024-08-22 14:09:59 -04:00
759b19e444 Update README.md 2024-08-22 12:23:21 -04:00
36f705e46f Update README.md 2024-08-22 12:23:09 -04:00
1f0347682e Merge pull request #4553 from oqtane/master
5.2.1 Release
2024-08-22 12:15:38 -04:00
1aee385679 Merge pull request #4552 from oqtane/dev
5.2.1 Release
2024-08-22 12:15:15 -04:00
5dd8191692 Merge pull request #4551 from sbwalker/dev
fixed required field validation in Search Results Settings
2024-08-22 12:10:34 -04:00
b6422f9b80 fixed required field validation in Search Results Settings 2024-08-22 12:10:15 -04:00
a6c2c9c92f Merge pull request #4550 from sbwalker/dev
use localized Yes/No values when displaying Site Urls Default? option
2024-08-22 10:53:43 -04:00
247c573a6e use localized Yes/No values when displaying Site Urls Default? option 2024-08-22 10:53:27 -04:00
aa435d6e94 Merge pull request #4548 from sbwalker/dev
fix #4546 - handle cache invalidation for site deletion
2024-08-22 08:26:44 -04:00
f6858c221b fix #4546 - handle cache invalidation for site deletion 2024-08-22 08:26:29 -04:00
437aa4510b Merge pull request #4547 from sbwalker/dev
fix #4545 - Site Settings - UI Component Settings changes not refreshed after saving
2024-08-22 08:09:18 -04:00
430572fb32 fix #4545 - Site Settings - UI Component Settings changes not refreshed after saving 2024-08-22 08:08:55 -04:00
9f0b755d6f Merge pull request #4543 from sbwalker/dev
fix login redirect issue in sub-site where user has navigated directly to login page
2024-08-21 15:17:47 -04:00
66acb55a57 fix login redirect issue in sub-site where user has navigated directly to login page 2024-08-21 15:17:29 -04:00
f936d4c36e Merge pull request #4542 from sbwalker/dev
fix #4536 - deleted modules appearing in Page Management - Modules panel
2024-08-20 16:18:45 -04:00
c3ddb8df56 fix #4536 - deleted modules appearing in Page Management - Modules panel 2024-08-20 16:18:31 -04:00
81ce920e69 Merge pull request #4541 from sbwalker/dev
fix issues in default template for Interactive Client (WebAssembly) scenarios
2024-08-20 15:34:05 -04:00
3cb875d139 fix issues in default template for Interactive Client (WebAssembly) scenarios 2024-08-20 15:33:46 -04:00
fdb217d5c6 Merge pull request #4540 from sbwalker/dev
set BaseAddress for IHttpClientFactory
2024-08-20 15:22:39 -04:00
085cae3b5f set BaseAddress for IHttpClientFactory 2024-08-20 15:22:27 -04:00
e2f99a1554 Merge pull request #4538 from sbwalker/dev
fix #4498 build ServerState Assemblies collection in a more thread safe manner
2024-08-20 14:03:02 -04:00
aee0c27da7 fix #4498 build ServerState Assemblies collection in a more thread safe manner 2024-08-20 14:02:37 -04:00
accbf4ad8b Merge pull request #4535 from sbwalker/dev
use existing SiteKey
2024-08-20 08:35:36 -04:00
0ac1901f6b use existing SiteKey 2024-08-20 08:35:23 -04:00
c0a0deea78 Merge pull request #4532 from sbwalker/dev
ensure form name is unique in ActionDialog
2024-08-19 16:58:48 -04:00
e3f099441c ensure form name is unique in ActionDialog 2024-08-19 16:58:33 -04:00
840dd25cd1 Merge pull request #4530 from sbwalker/dev
fix issues with ActionDialog in static rendering
2024-08-19 09:34:23 -04:00
a493969f9b fix issues with ActionDialog in static rendering 2024-08-19 09:34:08 -04:00
cca42a10a1 Merge pull request #4529 from sbwalker/dev
fix CSS
2024-08-19 09:05:00 -04:00
2f4aa98c3c fix CSS 2024-08-19 09:04:46 -04:00
175cb9588c Merge pull request #4524 from sbwalker/dev
prevent scroll position from resetting to top of page when querystring or hash changes
2024-08-16 15:01:43 -04:00
a8976e7559 prevent scroll position from resetting to top of page when querystring or hash changes 2024-08-16 15:01:25 -04:00
b663528fb0 Merge pull request #4521 from sbwalker/dev
add ability to extract zip file contents in File Management
2024-08-14 15:54:30 -04:00
1a2ad55677 add ability to extract zip file contents in File Management 2024-08-14 15:54:13 -04:00
513d2a88c0 Merge pull request #4520 from sbwalker/dev
move HtmlText caching from repository to service layer
2024-08-14 10:01:11 -04:00
57ef4c0396 move HtmlText caching from repository to service layer 2024-08-14 10:00:56 -04:00
e9599ca2f4 Merge pull request #4519 from sbwalker/dev
fix #4517 - index error due to duplicate records on upgrade
2024-08-14 08:19:28 -04:00
2fc6dbc222 fix #4517 - index error due to duplicate records on upgrade 2024-08-14 08:19:14 -04:00
225933c442 Merge pull request #4518 from sbwalker/dev
update nuspec files for 5.2.1
2024-08-14 08:12:46 -04:00
36e2f048d7 update nuspec files for 5.2.1 2024-08-14 08:12:31 -04:00
0e158bce59 Merge pull request #4515 from thabaum/update-version-5.2.1-and-dependencies
Fixes #4514 - Update version 5.2.1 and dependencies
2024-08-14 07:58:55 -04:00
202201fd31 Merge pull request #4516 from ijaz-saeed/dev
search settings translation entry
2024-08-14 07:55:11 -04:00
4f8c928f44 search settings translation entry 2024-08-14 11:57:06 +05:00
ada062cf00 Update version to 5.2.1 and dependencies 2024-08-13 15:53:45 -07:00
32dc12912a Update dependencies 2024-08-13 15:51:49 -07:00
671d21adf4 Update dependencies 2024-08-13 15:50:56 -07:00
4e3f8e4b67 Update dependencies 2024-08-13 15:49:15 -07:00
586bb62073 Update version to 5.2.1 and dependencies 2024-08-13 15:48:32 -07:00
151bf83ab1 Update version to 5.2.1 and dependencies 2024-08-13 15:46:45 -07:00
8c618edb5a Update version to 5.2.1 2024-08-13 15:45:23 -07:00
6d6b0cf8c9 Update version to 5.2.1 and dependencies 2024-08-13 15:44:45 -07:00
c610608890 Update version to 5.2.1 and dependencies 2024-08-13 15:43:27 -07:00
28da61daab Update version 5.2.1 and dependencies 2024-08-13 15:39:15 -07:00
cbfc90f60b Update Version To 5.2.1 and Dependencies To Latest 2024-08-13 15:36:20 -07:00
fec92959d4 Merge pull request #4513 from sbwalker/dev
move folder permissions grid to dedicated tab for consistency
2024-08-13 16:48:34 -04:00
bb00d81eba move folder permissions grid to dedicated tab for consistency 2024-08-13 16:48:22 -04:00
bb55644c06 Merge pull request #4512 from sbwalker/dev
improve file name and extension validation
2024-08-12 17:02:22 -04:00
16215847cd improve file name and extension validation 2024-08-12 17:02:07 -04:00
8ee9aed817 Merge pull request #4509 from sbwalker/dev
improve SettingService
2024-08-12 10:20:56 -04:00
515c6402b9 improve SettingService 2024-08-12 10:20:44 -04:00
d1b94ec203 Merge pull request #4507 from leigh-pointer/Permissions-4503
Fix for #4503 Module Custom Permissions not being shown
2024-08-10 17:54:51 -04:00
a037d9167e Fix for #4503 Module Custom Permissions not being shown 2024-08-10 21:25:32 +02:00
3054d33e62 Merge pull request #4493 from thabaum/set-samesite-lax-visitor-culture-cookies
Fix #4492: Updates Culture and Visitor cookies to use "Lax" SameSite and Secure Cookie Options
2024-08-10 14:08:01 -04:00
6651e641e1 Merge pull request #4505 from sbwalker/dev
add search reindex capability
2024-08-10 10:02:08 -04:00
35f873a342 add search reindex capability 2024-08-10 10:01:52 -04:00
2d03ff38a1 Merge pull request #4504 from sbwalker/dev
replace dynamic query with linq
2024-08-09 17:16:30 -04:00
44a3db417b replace dynamic query with linq 2024-08-09 17:16:17 -04:00
f9ca702a12 Merge pull request #4502 from sbwalker/dev
fix #4499 - page modules not loaded properly
2024-08-09 13:11:31 -04:00
4073ff38eb fix #4499 - page modules not loaded properly 2024-08-09 13:11:19 -04:00
f0e2c9f1b6 Merge pull request #4501 from sbwalker/dev
eliminate database call for authenticated users
2024-08-09 13:00:35 -04:00
cf040f51b5 eliminate database call for authenticated users 2024-08-09 13:00:20 -04:00
dcf919fb36 Adds AntiForgery Cookie setting options.Cookie.HttpOnly = true; 2024-08-08 12:24:42 -07:00
aa19b81a68 Merge pull request #4487 from leigh-pointer/TemplateUpdate
Update Theme Template to Bootstrap 5.3.3
2024-08-08 14:44:27 -04:00
db8d77365c Merge pull request #4479 from pollux/patch-1
Fix admin/pages not showing 404 for unauthorized users
2024-08-08 14:42:08 -04:00
280eaea84a Merge pull request #4497 from sbwalker/dev
improve search result performance and relevancy
2024-08-08 14:11:43 -04:00
340ef46469 improve search result performance and relevancy 2024-08-08 14:11:27 -04:00
a5f8651941 Revert previous cookie HttpOnly option 2024-08-07 16:24:18 -07:00
8a18ee548e Merge pull request #4494 from sbwalker/dev
add missing indexes
2024-08-07 16:55:48 -04:00
ef791aa22a add missing indexes 2024-08-07 16:55:35 -04:00
4bdf2e1cc0 Update AntiForgery Token Cookie Option to HTTPOnly = true; 2024-08-07 13:21:18 -07:00
ffa0ca9379 Updates Culture and Visitor cookies to use "Lax" SameSite and Secure cookie options 2024-08-07 11:52:53 -07:00
d3b3d46fc1 Return to standard Bootstrap 2024-08-07 20:01:41 +02:00
7e7dd8efa9 Update Theme Template to Bootstrap 5.3.3 2024-08-07 10:34:40 +02:00
b4506f1133 Merge pull request #4483 from sbwalker/dev
include "://" on default Alias Protocol for consistency
2024-08-05 07:51:07 -04:00
7350c79113 include "://" on default Alias Protocol for consistency 2024-08-05 07:50:54 -04:00
5f7b60d3f4 Merge pull request #4480 from leigh-pointer/Log2xHttp
Removed the extra "://" from the Log Manager
2024-08-05 07:50:06 -04:00
266495a611 Removed the extra ";//" from the Log Manager
{alias.Protocol} return with ";//"
2024-08-03 12:26:33 +02:00
f5b4a7e77b Fix admin/pages not showing 404 for unauthorized users 2024-08-02 11:49:55 +02:00
51ed0f6487 Merge pull request #4472 from sbwalker/dev
fix #4471 - search pages not being added on upgrade
2024-07-27 09:51:22 -04:00
bd70def18a fix #4471 - search pages not being added on upgrade 2024-07-27 09:51:02 -04:00
93a9cf3b31 Update README.md 2024-07-25 13:22:02 -04:00
751287999f Update README.md 2024-07-25 11:57:24 -04:00
d433850cbf Merge pull request #4469 from oqtane/master
5.2.0 release
2024-07-25 11:49:12 -04:00
c93e70e2dc Merge pull request #4468 from oqtane/dev
5.2.0 release
2024-07-25 11:48:50 -04:00
a129dd989a Merge pull request #4467 from sbwalker/dev
remove Settings button logic from QuillJS text editor interop
2024-07-25 11:13:19 -04:00
40999c3ff4 remove Settings button logic from QuillJS text editor interop 2024-07-25 11:12:58 -04:00
18a01d672c Merge pull request #4466 from sbwalker/dev
resolve localization issue in ActionDialog
2024-07-25 09:24:34 -04:00
3648f99920 resolve localization issue in ActionDialog 2024-07-25 09:24:21 -04:00
e823412f56 Merge pull request #4465 from leigh-pointer/NotifyLogging
Small Notification Job update
2024-07-25 08:47:00 -04:00
d090f446c9 Small Notification Job update
This update adds the NotificationId to the log to help track down any errors.
2024-07-25 13:11:05 +02:00
19985d1742 Merge pull request #4464 from sbwalker/dev
resolve issue with default Blazor theme
2024-07-24 13:00:03 -04:00
ab52251116 resolve issue with default Blazor theme 2024-07-24 12:59:40 -04:00
acb6c0187c Merge pull request #4461 from sbwalker/dev
add missing localization for Search Results Settings
2024-07-23 14:44:30 -04:00
90f9c24720 add missing localization for Search Results Settings 2024-07-23 14:44:14 -04:00
415bec4646 Merge pull request #4460 from sbwalker/dev
prevent breaking change for interactive components referencing PageState.Pages
2024-07-23 12:48:13 -04:00
5559f20511 prevent breaking change for interactive components referencing PageState.Pages 2024-07-23 12:47:54 -04:00
6ea3399829 Merge pull request #4458 from sbwalker/dev
use PageState.Site.Settings rather than reloading settings from database
2024-07-23 07:45:32 -04:00
9e3df97737 use PageState.Site.Settings rather than reloading settings from database 2024-07-23 07:45:13 -04:00
0ac40a4d77 Merge pull request #4456 from leigh-pointer/SixLabors.ImageSharp
ENH update to 3.1.5 #4455 Vulnerabilities detected in 3.1.4
2024-07-23 07:13:45 -04:00
24bf5e8102 Merge pull request #4454 from mdmontesinos/dev
fix: set Rich active tab for Quill text editor
2024-07-23 07:13:24 -04:00
56eebb03c7 Merge pull request #4457 from sbwalker/dev
change IsEffectiiveOrExpired to IsEffectiveAndNotExpired
2024-07-23 07:11:31 -04:00
1cd4d6d0df change IsEffectiiveOrExpired to IsEffectiveAndNotExpired 2024-07-23 07:08:26 -04:00
22d4a8232a ENH update to 3.1.5 #4455 Vulnerabilities detected in 3.1.4 2024-07-23 13:03:03 +02:00
48076c25bf fix: set Rich active tab for Quill text editor 2024-07-23 09:18:58 +02:00
478a308e73 Merge pull request #4453 from sbwalker/dev
fix #4284 - handle user role effective and expiry date
2024-07-22 21:09:52 -04:00
8ca2f0a49f fix #4284 - handle user role effective and expiry date 2024-07-22 21:09:35 -04:00
4a35d7364b Merge pull request #4452 from sbwalker/dev
remove ITextEditorProvider interface
2024-07-22 13:31:39 -04:00
8b2e55a969 remove ITextEditorProvider interface 2024-07-22 13:31:24 -04:00
9b14b70687 Merge pull request #4451 from sbwalker/dev
fix #4450 QuillJSTextEditor settings
2024-07-22 08:11:24 -04:00
1c01087eda fix #4450 QuillJSTextEditor settings 2024-07-22 08:11:09 -04:00
5137e5a301 Merge pull request #4449 from sbwalker/dev
add documentation
2024-07-21 09:19:00 -04:00
0fea8365b8 add documentation 2024-07-21 09:18:41 -04:00
116a615b84 Merge pull request #4448 from sbwalker/dev
change Ignore Paths to Ignore Pages
2024-07-21 09:10:23 -04:00
ef272dd6a8 change Ignore Paths to Ignore Pages 2024-07-21 09:10:01 -04:00
4462ae9cae Merge pull request #4447 from sbwalker/dev
moved Search Provider setting to Search Settings
2024-07-21 08:59:41 -04:00
66ffad0b4e moved Search Provider setting to Search Settings 2024-07-21 08:59:23 -04:00
81e0fc940c Merge pull request #4446 from sbwalker/dev
add Search Provider to Site Settings
2024-07-21 08:49:38 -04:00
3e8794db1b add Search Provider to Site Settings 2024-07-21 08:49:18 -04:00
617622d4d8 Merge pull request #4445 from sbwalker/dev
add Functionality section to Site Settings
2024-07-21 08:16:10 -04:00
a4240f972b add Functionality section to Site Settings 2024-07-21 08:15:51 -04:00
42feff8882 Merge pull request #4443 from sbwalker/dev
more localization changes
2024-07-20 21:52:56 -04:00
70edd9686f more localization changes 2024-07-20 21:52:41 -04:00
d298cb2e1c Merge pull request #4442 from sbwalker/dev
fix localization for QuillJSTextEditor
2024-07-20 21:43:57 -04:00
3fef3f2dc3 fix localization for QuillJSTextEditor 2024-07-20 21:43:38 -04:00
c85f9d6ae4 Merge pull request #4440 from sbwalker/dev
remove unecessary using
2024-07-20 19:39:58 -04:00
85e7ac7cd7 remove unecessary using 2024-07-20 19:39:45 -04:00
5c7db61a7e Merge pull request #4439 from sbwalker/dev
improve validation of seach content
2024-07-20 19:18:06 -04:00
497f9ca0b1 improve validation of seach content 2024-07-20 19:17:47 -04:00
0c50f7a322 Merge pull request #4438 from sbwalker/dev
allow page-script to support exterrnal JavaScript
2024-07-19 15:42:35 -04:00
740bcbd12c allow page-script to support exterrnal JavaScript 2024-07-19 15:42:20 -04:00
c92be4f270 Merge pull request #4437 from sbwalker/dev
revert modification done for testing purposes only
2024-07-19 15:31:24 -04:00
e2a7271ab2 revert modification done for testing purposes only 2024-07-19 15:31:11 -04:00
64766713fa Merge pull request #4436 from sbwalker/dev
add ability to manage search results settings
2024-07-19 12:56:14 -04:00
59bba83b1d add ability to manage search results settings 2024-07-19 12:55:59 -04:00
8ac1217165 Merge pull request #4435 from sbwalker/dev
allow <style> tags to be injected using HeadContent
2024-07-18 15:01:43 -04:00
5443629ec5 allow <style> tags to be injected using HeadContent 2024-07-18 15:01:20 -04:00
8f9b41cb62 Merge pull request #4434 from sbwalker/dev
use JSInterop for loading QuillJSTextEditor stylesheet
2024-07-18 13:17:58 -04:00
7df5eba775 use JSInterop for loading QuillJSTextEditor stylesheet 2024-07-18 13:17:23 -04:00
e29c6ac593 Merge pull request #4433 from sbwalker/dev
improve search user experience
2024-07-18 11:50:07 -04:00
4f3190bf73 improve search user experience 2024-07-18 11:49:42 -04:00
f0878fccb5 Merge pull request #4432 from sbwalker/dev
fix ISearchable implementation in default module template
2024-07-18 11:10:39 -04:00
b0e121a53f fix ISearchable implementation in default module template 2024-07-18 11:10:24 -04:00
eda48ab0e6 Merge pull request #4431 from sbwalker/dev
QuillJSTextEditor setting improvements
2024-07-18 11:03:13 -04:00
6a1014d8c1 QuillJSTextEditor setting improvements 2024-07-18 11:01:01 -04:00
e0f87315bc Merge pull request #4430 from sbwalker/dev
set Prerender on Login component
2024-07-17 20:52:28 -04:00
f2c5dca5e7 set Prerender on Login component 2024-07-17 20:52:13 -04:00
3c435a804f Merge pull request #4429 from sbwalker/dev
remove hardcoded names when using GetInterface()
2024-07-17 19:53:06 -04:00
7ee6775251 remove hardcoded names when using GetInterface() 2024-07-17 19:52:44 -04:00
98adc2ecc1 Merge pull request #4428 from sbwalker/dev
allow search content permissions to support roles
2024-07-17 19:34:34 -04:00
45afbbdac6 allow search content permissions to support roles 2024-07-17 19:34:19 -04:00
a18260747b Merge pull request #4427 from sbwalker/dev
add Refresh option for Job Logs
2024-07-17 17:12:38 -04:00
0c80e28754 add Refresh option for Job Logs 2024-07-17 17:12:24 -04:00
719bc374ac Merge pull request #4426 from sbwalker/dev
add localization to search settings
2024-07-17 16:34:16 -04:00
d7a290c595 add localization to search settings 2024-07-17 16:34:02 -04:00
4b2bd33baa Merge pull request #4425 from sbwalker/dev
update theme template to .NET 8.0.7
2024-07-17 16:23:30 -04:00
efbe4d697c update theme template to .NET 8.0.7 2024-07-17 16:23:15 -04:00
a8662bdb8b Merge pull request #4424 from sbwalker/dev
use Task.FromResult()
2024-07-17 16:22:16 -04:00
d822225465 use Task.FromResult() 2024-07-17 16:22:01 -04:00
c6373ef582 Merge pull request #4423 from sbwalker/dev
update module template to .NET 8.0.7
2024-07-17 16:17:30 -04:00
5a2af6d0f9 update module template to .NET 8.0.7 2024-07-17 16:17:10 -04:00
52000d6a41 Merge pull request #4422 from sbwalker/dev
update to .NET 8.0.7
2024-07-17 15:10:54 -04:00
befa13eaf2 update to .NET 8.0.7 2024-07-17 15:10:40 -04:00
4ac68a81a3 Merge pull request #4421 from sbwalker/dev
search optimizations
2024-07-17 13:58:03 -04:00
71e472f330 search optimizations 2024-07-17 13:57:47 -04:00
ada8809ec0 Merge pull request #4420 from oqtane/revert-4417-dev
Revert "disable prerendering by default for static rendered sites"
2024-07-17 12:13:35 -04:00
25ea518266 Revert "revert #4250 which disabled prerendering by default for static rendered sites" 2024-07-17 12:12:58 -04:00
f3720c3b94 Merge pull request #4419 from sbwalker/dev
improve PageState trimming
2024-07-17 11:53:22 -04:00
b942a84b15 improve PageState trimming 2024-07-17 11:53:04 -04:00
574ca90229 Merge pull request #4418 from sbwalker/dev
add missing properties to Clone method
2024-07-17 11:34:15 -04:00
5610a14e49 add missing properties to Clone method 2024-07-17 11:34:01 -04:00
c5bc62e6df Merge pull request #4417 from sbwalker/dev
revert #4250 which disabled prerendering by default for static rendered sites
2024-07-17 11:22:18 -04:00
e9f6a85cad revert #4250 which disabled prerendering by default for static rendered sites 2024-07-17 11:20:27 -04:00
8921011b27 Merge pull request #4416 from sbwalker/dev
performance improvement in Control Panel to only load list of pages when necessary
2024-07-17 11:13:46 -04:00
90ef3f6c94 performance improvement in Control Panel to only load list of pages when necessary 2024-07-17 11:13:27 -04:00
e84c75f4a8 Merge pull request #4414 from pollux/patch-1
Update Oqtane.Shared.csproj
2024-07-17 11:09:59 -04:00
68e20cd860 Merge pull request #4415 from sbwalker/dev
include Search Settings
2024-07-17 11:09:00 -04:00
76bdcea4b1 include Search Settings 2024-07-17 11:08:43 -04:00
f758cb7e6e Update Oqtane.Shared.csproj
Fixes CVE-2024-30105
2024-07-17 12:46:49 +02:00
1108477810 Merge pull request #4413 from sbwalker/dev
make SearchResults API consistent with other core APIs
2024-07-16 16:55:09 -04:00
deb6a9e51c make SearchResults API consistent with other core APIs 2024-07-16 16:54:55 -04:00
9660f20b87 Merge pull request #4412 from sbwalker/dev
performance optimization to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
2024-07-16 16:21:57 -04:00
4d26468ede performance optimization to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries 2024-07-16 16:21:35 -04:00
125a0979d5 Merge pull request #4408 from sbwalker/dev
removed unused constants
2024-07-15 10:11:31 -04:00
98bdfd3dbe removed unused constants 2024-07-15 10:11:14 -04:00
ea72880e74 Merge pull request #4407 from sbwalker/dev
resolve security issue in Search
2024-07-15 10:08:04 -04:00
17fec7d6e1 resolve security issue in Search 2024-07-15 10:07:48 -04:00
d9de64604e Merge pull request #4406 from sbwalker/dev
fix #4401 - avoid mutating Site object in cache
2024-07-15 08:37:46 -04:00
6275ab23ff fix #4401 - avoid mutating Site object in cache 2024-07-15 08:37:23 -04:00
8c0271643d Merge pull request #4405 from sbwalker/dev
testing search indexing of files
2024-07-13 09:28:25 -04:00
c3f041dc87 testing search indexing of files 2024-07-13 09:28:02 -04:00
80e5e84341 Merge pull request #4404 from sbwalker/dev
only include pages in index if they do not have any modules
2024-07-12 10:53:25 -04:00
938eee80a9 only include pages in index if they do not have any modules 2024-07-12 10:52:58 -04:00
7abc2289de Merge pull request #4402 from sbwalker/dev
search modifications
2024-07-12 10:33:34 -04:00
bb79b9ed74 search modifications 2024-07-12 10:33:17 -04:00
1e89a8625c Merge pull request #4400 from sbwalker/dev
fix #4397 - remove incorrect help text
2024-07-11 13:39:19 -04:00
90b0f04b3c fix #4397 - remove incorrect help text 2024-07-11 13:39:05 -04:00
0f019cd9b6 Merge pull request #4399 from sbwalker/dev
fix #4398 - InputList component not handling scenario where input is reset to nothing
2024-07-11 13:36:14 -04:00
1209739398 fix #4398 - InputList component not handling scenario where input is reset to nothing 2024-07-11 13:35:46 -04:00
b99db2b353 Merge pull request #4394 from sbwalker/dev
more Site Settings for search configuration
2024-07-08 16:59:10 -04:00
f057688e7d more Site Settings for search configuration 2024-07-08 16:58:55 -04:00
12ae2d0c76 Merge pull request #4393 from sbwalker/dev
site settings to configure indexing
2024-07-08 14:33:54 -04:00
9d91d5a127 site settings to configure indexing 2024-07-08 14:33:16 -04:00
6015f0887a Merge pull request #4389 from sbwalker/dev
fix #4384 - app_offline https link
2024-07-06 08:38:52 -04:00
d4c473d7b3 fix #4384 - app_offline https link 2024-07-06 08:38:33 -04:00
2f3978deed Merge pull request #4374 from zyhfish/task/fix-issue-4358
Fix #4358: RichTextEditor Provider Abstraction.
2024-07-06 08:32:19 -04:00
34af53a15b Merge branch 'dev' into task/fix-issue-4358 2024-07-06 08:32:10 -04:00
a4eb3d7a0b Merge pull request #4388 from sbwalker/dev
search refactoring
2024-07-06 07:58:35 -04:00
5b46dd7293 search refactoring 2024-07-06 07:58:04 -04:00
4b17847ea5 Merge remote-tracking branch 'oqtane/dev' into dev 2024-07-05 21:53:14 -07:00
Ben
acbe000f97 avoid race condition issue. 2024-07-03 17:59:40 +08:00
Ben
599071b68b avoid race condition issue. 2024-07-03 17:07:47 +08:00
Ben
2bacee919d update the settings UI. 2024-07-03 12:26:36 +08:00
50d35e4196 Merge pull request #4383 from sbwalker/dev
remove unnecessary using
2024-07-02 15:53:40 -04:00
e321998b85 remove unnecessary using 2024-07-02 15:53:26 -04:00
340c02b2af Merge pull request #4382 from sbwalker/dev
remove unnecessary database call to GetPage
2024-07-02 15:45:59 -04:00
69a295fe57 remove unnecessary database call to GetPage 2024-07-02 15:45:44 -04:00
64830aae9f Merge pull request #4381 from sbwalker/dev
use PageModule in ISearchable
2024-07-02 14:50:42 -04:00
8969b1273f use PageModule in ISearchable 2024-07-02 14:50:26 -04:00
475faf7943 Merge pull request #4380 from sbwalker/dev
fix #4375 - deleted pages not being filtered
2024-07-02 11:05:42 -04:00
45b1d405a6 fix #4375 - deleted pages not being filtered 2024-07-02 11:05:29 -04:00
Ben
f60c8078e4 cleanup the code. 2024-07-02 09:55:38 +08:00
Ben
6701e49f9a move the editor settings into editor self control. 2024-07-02 09:50:53 +08:00
0efb3c3284 Merge pull request #4376 from sbwalker/dev
ensure UniqueKey is unique by including TenantId and SiteId
2024-07-01 16:20:15 -04:00
aaf3cdfdac ensure UniqueKey is unique by including TenantId and SiteId 2024-07-01 16:19:58 -04:00
Ben
e00c261777 Fix #4358: RichTextEditor Provider Abstraction. 2024-07-01 17:11:26 +08:00
1eafed755d Merge pull request #4372 from sbwalker/dev
provide default Permissions value
2024-06-28 17:31:48 -04:00
7f6a08ae50 provide default Permissions value 2024-06-28 17:31:33 -04:00
9901816fb9 Merge pull request #4371 from sbwalker/dev
ensure ModuleDefinition exists
2024-06-28 17:26:58 -04:00
3cbe6c1e95 ensure ModuleDefinition exists 2024-06-28 17:26:46 -04:00
679c99274e Merge pull request #4370 from sbwalker/dev
change EntityId to string
2024-06-28 16:25:11 -04:00
b6fa0f1ff6 change EntityId to string 2024-06-28 16:24:56 -04:00
9ff64b95e1 Merge pull request #4369 from sbwalker/dev
modify query property names
2024-06-28 16:15:42 -04:00
3a9885abd8 modify query property names 2024-06-28 16:15:28 -04:00
503210942c Merge pull request #4368 from sbwalker/dev
breaking search modifications into smaller PRs
2024-06-28 15:44:11 -04:00
0178e015e3 breaking search modifications into smaller PRs 2024-06-28 15:43:54 -04:00
7604992c35 Merge pull request #4361 from 2sic-forks/bug/4360
fix docfx build issues #4360
2024-06-28 09:01:45 -04:00
ee9e551788 Merge pull request #4365 from sbwalker/dev
reposition Search input in themes
2024-06-27 17:18:54 -04:00
22063248ca reposition Search input in themes 2024-06-27 17:18:41 -04:00
e4ce18b35c Merge pull request #4364 from sbwalker/dev
eager load Page associated to PageModule
2024-06-27 17:05:35 -04:00
532890674e eager load Page associated to PageModule 2024-06-27 17:05:22 -04:00
791a3b67e6 fix docfx build issues 2024-06-27 19:47:13 +02:00
84b560ef29 Merge pull request #4356 from sbwalker/dev
fix #4353 - add defensive logic when sending notifications and improve performance
2024-06-26 09:09:29 -04:00
03f081f3f4 fix #4353 - add defensive logic when sending notifications and improve performance 2024-06-26 09:09:06 -04:00
08213ae86e Merge pull request #4352 from sbwalker/dev
fix #4349 - adding module in subsite in Interactive render mode
2024-06-24 16:27:35 -04:00
73abc511a8 fix #4349 - adding module in subsite in Interactive render mode 2024-06-24 16:26:55 -04:00
1c943cc259 Merge pull request #4350 from sbwalker/dev
fix #4339 - add page not redirecting to correct url in subsite
2024-06-24 11:00:01 -04:00
af62a89a6b fix #4339 - add page not redirecting to correct url in subsite 2024-06-24 10:59:34 -04:00
af7ca5b897 Merge pull request #4338 from sbwalker/dev
use List instead of IList, remove "List" from method names. remove unnecessary using statements
2024-06-11 10:39:03 -04:00
27356ef747 use List instead of IList, remove "List" from method names. remove unnecessary using statements 2024-06-11 10:38:44 -04:00
b27f80ef87 Merge pull request #4337 from leigh-pointer/SearchResultsCat
Updated SearchResults Categories to Admin
2024-06-11 10:28:56 -04:00
b4aa73fc64 Updated SearchResults Categories to Admin 2024-06-11 15:21:12 +02:00
bbf444572b Merge pull request #4336 from sbwalker/dev
removed IHttpContextAccessor as it shoudl not be used in Blazor,  fixed form handling, added Reset button to consistent with other framework search options, used SharedLocalizer, removed unused localization keys
2024-06-11 08:39:28 -04:00
b3706574de removed IHttpContextAccessor as it shoudl not be used in Blazor, fixed form handling, added Reset button to consistent with other framework search options, used SharedLocalizer, removed unused localization keys 2024-06-11 08:38:51 -04:00
83062f8bfb Merge pull request #4335 from sbwalker/dev
fix ISearchable method name in module template
2024-06-11 07:37:25 -04:00
1d7fcfdaa1 fix ISearchable method name in module template 2024-06-11 07:37:02 -04:00
58ab12b4cb Merge pull request #4328 from leigh-pointer/UpdateTemplates
Update Project Templates from 8.0.5 - 8.0.6
2024-06-11 07:35:02 -04:00
28c649629f Merge pull request #4334 from leigh-pointer/Bootstrap5.3.3
Upgrade to Bootstrap 5.3.3
2024-06-11 07:32:10 -04:00
5ec190225d Upgrade to Bootstrap 5.3.3
Oqtane ThemeInfo updated
Blazor Default.razor updated
2024-06-11 09:51:48 +02:00
0e0d404997 Update [Module]Manager.cs 2024-06-11 09:11:25 +02:00
3f16b908ca Merge remote-tracking branch 'upstream/dev' into UpdateTemplates 2024-06-11 08:49:28 +02:00
54549b261c Merge pull request #4333 from sbwalker/dev
change IList to List for consistency with rest of framework
2024-06-10 17:17:33 -04:00
8ce07ced9e change IList to List for consistency with rest of framework 2024-06-10 17:17:20 -04:00
37a5144e8f Merge pull request #4332 from sbwalker/dev
update app constant to 5.2.0
2024-06-10 16:50:45 -04:00
59fed7dda8 update app constant to 5.2.0 2024-06-10 16:50:33 -04:00
0a85a2868c Merge pull request #4331 from sbwalker/dev
fix issue with primary key on SearchContentWord table
2024-06-10 16:47:45 -04:00
0d493b3250 fix issue with primary key on SearchContentWord table 2024-06-10 16:47:32 -04:00
74530d4b1e Merge pull request #4330 from sbwalker/dev
remove unnecessary using statements
2024-06-10 16:23:10 -04:00
7548c52e21 remove unnecessary using statements 2024-06-10 16:22:58 -04:00
fa49844c64 Merge pull request #4329 from sbwalker/dev
remove List from method name to conform to Oqtane naming conventions
2024-06-10 16:17:19 -04:00
3508ae1e0a remove List from method name to conform to Oqtane naming conventions 2024-06-10 16:17:05 -04:00
f013ee64a2 Updated Module Template with ISearchable implementation 2024-06-10 22:10:39 +02:00
af3da7ca6e update to template.json files to align with Oqtane version 2024-06-10 21:54:44 +02:00
cb728f65b3 Update Project Templates from 8.0.5 - 8.0.6 2024-06-10 21:50:30 +02:00
af6af190cc Merge pull request #4325 from thabaum/update-package-dependences-v5.2.0
Fixes #4324: Updates package dependences and prepares v5.2.0 release
2024-06-10 15:06:08 -04:00
cbcc8455ca Merge pull request #4326 from sbwalker/dev
refactored to move AdminSiteTemplate out of SiteRepository
2024-06-10 14:55:21 -04:00
af35fb79fe refactored to move AdminSiteTemplate out of SiteRepository 2024-06-10 14:55:06 -04:00
0515aaa946 Prepare v5.2.0 Release 2024-06-10 10:48:46 -07:00
1d00330e7a Prepare v5.2.0 Release and Package Dependencies 2024-06-10 10:48:18 -07:00
3fa6dcea16 Prepare v5.2.0 Release and Package Dependencies 2024-06-10 10:47:03 -07:00
51425cac4a Prepare v5.2.0 Release 2024-06-10 10:44:40 -07:00
7ce61a5d2b Prepare v5.2.0 Release 2024-06-10 10:43:54 -07:00
5e5caa979b Prepare v5.2.0 Release 2024-06-10 10:43:19 -07:00
a719518f8f Prepare v5.2.0 Release 2024-06-10 10:42:57 -07:00
d0e5aef443 Prepare v5.2.0 Release 2024-06-10 10:42:32 -07:00
b82a811c33 Prepare v5.2.0 Release and Package Dependencies 2024-06-10 10:41:51 -07:00
3356dcf8f7 Prepare v5.2.0 Release 2024-06-10 10:41:10 -07:00
8f1cc26537 Prepare v5.2.0 Release 2024-06-10 10:40:50 -07:00
27dafa83ac Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:38:52 -07:00
c1be1f329f Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:37:51 -07:00
c757cef549 Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:37:21 -07:00
da9e4c026c Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:37:04 -07:00
5821d67e69 Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:36:47 -07:00
ed14f6d13f Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:35:43 -07:00
35bdd8b4ef Prepare Update v5.2.0 Package Dependencies 2024-06-10 10:35:16 -07:00
9cf2d30e77 Prepare Update v5.2.0 2024-06-10 10:32:30 -07:00
a2140a3b7b Update v5.2.0 Package Dependencies 2024-06-10 10:30:37 -07:00
900d026bcb Update v5.2.0 Package Dependencies 2024-06-10 10:29:58 -07:00
68604ec15a Update Oqtane.Database.PostgreSQL.csproj Package Dependencies 2024-06-10 10:28:51 -07:00
f7c0ebb8d3 Update Oqtane.Database.MySQL.csproj prepare 5.2.0 2024-06-10 10:27:53 -07:00
8be5d0c72d Update Oqtane.Database.MySQL.csproj Package Dependencies 2024-06-10 10:27:15 -07:00
15c8b724e6 Update Oqtane.Client.csproj Package Dependencies 2024-06-10 10:24:52 -07:00
d6949200f9 Merge pull request #4323 from sbwalker/dev
move Search page/module to Admin template so that it is always provisioned
2024-06-10 12:33:31 -04:00
1c2abe794a move Search page/module to Admin template so that it is always provisioned 2024-06-10 12:33:09 -04:00
0bcf393586 Merge pull request #4320 from sbwalker/dev
search refactoring
2024-06-08 16:24:32 -04:00
bc0573918f search refactoring 2024-06-08 16:14:56 -04:00
175675ad99 Merge pull request #4317 from zyhfish/task/fix-issue-4316
Fix #4316: add text editor interfaces.
2024-06-07 14:44:40 -04:00
Ben
b00c2afc46 Fix #4316: move the raw html editor into quill editor instance. 2024-06-07 08:35:42 +08:00
Ben
c125a7fe07 Fix #4316: add text editor interfaces. 2024-06-06 16:39:35 +08:00
a42ab32436 Merge pull request #4310 from zyhfish/task/fix-searchbox-responsive-issue
Fix #4309: make searchbox responsive.
2024-06-05 07:48:55 -04:00
797a64976e Merge pull request #4311 from fonsecaf/fix-cookie-date-culture-format
Fix Cookie Date Conversion to Respect Culture and Format
2024-06-05 07:48:43 -04:00
ac377a8b68 Modified date parsing and formatting to use invariant culture, ensuring consistency and preventing non-ASCII characters in HTTP headers. 2024-06-05 13:39:31 +10:00
Ben
842b7b1402 Fix #4309: make searchbox responsive. 2024-06-05 10:27:38 +08:00
d449396ad5 Merge pull request #4304 from zyhfish/task/add-search-function
#4303: add search function.
2024-06-04 16:52:10 -04:00
532a87d064 Merge pull request #4307 from leigh-pointer/OqtaneControls
Oqtane controls updates
2024-06-04 16:50:53 -04:00
Ben
e1cdc7b387 return the words count to calculate the ranking. 2024-06-04 21:57:50 +08:00
Ben
d9d917e267 set search result page path to be parameter. 2024-06-04 21:09:25 +08:00
8048788042 Oqtane controls updates
ActionDialog and ActionLink now allow other icon sets whilst still adhering to the legacy "oi oi-" icon set.
Pager added SearchBoxClass Class parameter to the Search div.
TabStrip added a TabContentClass Class parameter to the tab content div.
2024-06-04 12:21:59 +02:00
Ben
790fc88e47 using correct module id value. 2024-06-04 17:50:29 +08:00
Ben
7f970d489f refactoring the code. 2024-06-04 17:32:31 +08:00
Ben
9d85ca07f4 #4303: add search function. 2024-06-03 21:19:42 +08:00
d75e3acdf3 Merge pull request #4302 from sbwalker/dev
changes as a result of #4299 related to  PageState.Modules
2024-06-03 07:42:46 -04:00
694cda0e99 changes as a result of #4299 related to PageState.Modules 2024-06-03 07:42:22 -04:00
94f134c6a7 Merge pull request #4301 from zyhfish/task/fix-add-page-issue
Fix Add Page Issue
2024-06-01 09:04:28 -04:00
Ben
83f329d93c Fix Add Page Issue 2024-06-01 09:08:43 +08:00
de49387fca Merge pull request #4300 from sbwalker/dev
remove LoadTestingSiteTemplate
2024-05-31 16:51:45 -04:00
e5567f2f46 remove LoadTestingSiteTemplate 2024-05-31 16:51:27 -04:00
80f545f3d5 Merge pull request #4299 from sbwalker/dev
scalability improvements
2024-05-31 16:23:50 -04:00
06f0cc70b8 scalability improvements 2024-05-31 16:23:36 -04:00
cf6b7544b0 Update README.md 2024-05-28 15:20:37 -04:00
d511c6334a Update README.md 2024-05-28 15:20:15 -04:00
0224fd6d54 Update README.md 2024-05-28 15:17:27 -04:00
e95ae8dbcf Merge pull request #4295 from oqtane/master
5.1.2 release
2024-05-28 15:12:02 -04:00
5fbd64da71 Merge pull request #4294 from oqtane/dev
5.1.2 release
2024-05-28 15:11:34 -04:00
b282a2a621 Merge pull request #4291 from sbwalker/dev
introduce Clone method in Permission model
2024-05-28 07:56:01 -04:00
9a7a534051 introduce Clone method in Permission model 2024-05-28 07:55:45 -04:00
52fd030b6e Merge pull request #4286 from sbwalker/dev
fix issues when importing SiteTemplates
2024-05-24 22:51:57 -04:00
dfe530a764 fix issues when importing SiteTemplates 2024-05-24 22:51:34 -04:00
b079956075 Merge pull request #4283 from sbwalker/dev
add ability to specify session duration for visitor tracking
2024-05-23 09:44:59 -04:00
e30037c4d1 add ability to specify session duration for visitor tracking 2024-05-23 09:44:42 -04:00
eda7be627c Merge pull request #4281 from sbwalker/dev
fix #4279 - remove Theme Settings tab from Add Page UI
2024-05-21 11:06:55 -04:00
af0a649656 fix #4279 - remove Theme Settings tab from Add Page UI 2024-05-21 11:06:42 -04:00
8b6a3c4236 Merge pull request #4278 from sbwalker/dev
changed terminology from Library to Headless
2024-05-20 22:12:14 -04:00
0988a92d8a changed terminology from Library to Headless 2024-05-20 22:12:01 -04:00
9cf67764b7 Merge pull request #4277 from sbwalker/dev
update theme and module templates to .NET SDK 8.0.5
2024-05-20 16:59:56 -04:00
6c4e1d1c41 update theme and module templates to .NET SDK 8.0.5 2024-05-20 16:59:44 -04:00
b1cd1ea8b3 Merge pull request #4276 from sbwalker/dev
upgrade to .NET 8.0.5
2024-05-20 16:54:24 -04:00
5169ed494c upgrade to .NET 8.0.5 2024-05-20 16:54:11 -04:00
824211c31b Merge pull request #4275 from sbwalker/dev
prepare for 5.1.2 release
2024-05-20 16:42:48 -04:00
be3dd83bc7 prepare for 5.1.2 release 2024-05-20 16:42:35 -04:00
c2911c1e48 Merge pull request #4274 from sbwalker/dev
script formatting
2024-05-20 16:36:30 -04:00
9a66c5c07d script formatting 2024-05-20 16:36:17 -04:00
34d393b986 Merge pull request #4273 from sbwalker/dev
optimize scripts
2024-05-20 16:29:28 -04:00
d4da02318d optimize scripts 2024-05-20 16:29:12 -04:00
47162af6d5 Merge pull request #4272 from sbwalker/dev
improve validation in package extraction
2024-05-20 09:34:23 -04:00
8cd6a72dd3 improve validation in package extraction 2024-05-20 09:33:46 -04:00
ba0a183b6f Merge pull request #4271 from sbwalker/dev
fix #4249 - allow EmailConfirmed property to be updated
2024-05-20 08:54:33 -04:00
73781c7edb fix #4249 - allow EmailConfirmed property to be updated 2024-05-20 08:54:19 -04:00
6d99852c81 Merge pull request #4269 from sbwalker/dev
refactor #4268 to support static render mode
2024-05-19 09:05:56 -04:00
9325c726fd refactor #4268 to support static render mode 2024-05-19 09:05:35 -04:00
947bb8530e Merge pull request #4268 from zyhfish/task/fix-issue-3885
Fix #3885: only re-render the component when message changed.
2024-05-19 08:48:36 -04:00
Ben
2b32f316ee Fix #3885: only re-render the component when message changed. 2024-05-18 21:55:37 +08:00
4b1f23a189 Merge pull request #4266 from sbwalker/dev
improve scroll position navigation behavior
2024-05-17 15:42:26 -04:00
71d220e7a4 improve scroll position navigation behavior 2024-05-17 15:42:13 -04:00
747d0d0d17 Merge pull request #4265 from sbwalker/dev
fix #4246 - module message form exception when clicking close button
2024-05-17 14:12:02 -04:00
5c72e6d335 fix #4246 - module message form exception when clicking close button 2024-05-17 14:11:48 -04:00
e1ac2b0e10 Merge pull request #4264 from sbwalker/dev
set browser scroll position on navigation in Static Rendering
2024-05-17 13:01:20 -04:00
0ba94f3bc9 set browser scroll position on navigation in Static Rendering 2024-05-17 13:01:03 -04:00
ba0bfafcd5 Merge pull request #4263 from sbwalker/dev
fix redirect logic when adding a new page
2024-05-17 08:51:42 -04:00
81adb80b7e fix redirect logic when adding a new page 2024-05-17 08:51:28 -04:00
cb238ef170 Merge pull request #4262 from sbwalker/dev
fix #4224 - reload page after adding module in Static Rendering
2024-05-17 08:38:33 -04:00
b9b921de82 fix #4224 - reload page after adding module in Static Rendering 2024-05-17 08:38:22 -04:00
d10e31c278 Merge pull request #4261 from sbwalker/dev
fix #4232 - Html/Text module not initializing content
2024-05-16 15:39:30 -04:00
fd641d77c7 fix #4232 - Html/Text module not initializing content 2024-05-16 15:39:17 -04:00
2aa9710dd1 Merge pull request #4260 from leigh-pointer/Bug4259
Fix for #4259 Localizer Null in Module Settings
2024-05-16 15:14:28 -04:00
4afb2ef2b8 Fix for #4259 Localizer Null
removed the override string Title as it will be set Localized in the OnInitialized using SetModuleTitle base method.
2024-05-16 10:22:37 +02:00
a54e6e7c4b Merge pull request #4253 from zyhfish/task/fix-issue-4252
Fix #4252: do not reset the user photo setting when edit the user.
2024-05-13 08:51:33 -04:00
7af26a356f Merge pull request #4255 from zyhfish/task/fix-issue-4254
Fix #4254: remove the redundant space.
2024-05-13 08:49:22 -04:00
2f66165f8c Merge pull request #4256 from sbwalker/dev
add defensive logic to route parsing
2024-05-13 08:45:15 -04:00
e86ce8fc38 add defensive logic to route parsing 2024-05-13 08:45:03 -04:00
Ben
9b48c65129 Fix #4254: remove the redundant space. 2024-05-13 16:35:23 +08:00
Ben
434cd133df Fix #4252: do not reset the user photo setting when edit the user. 2024-05-13 16:08:43 +08:00
aa91e4cdee Merge pull request #4250 from sbwalker/dev
revert prerender changes and change default
2024-05-10 16:28:32 -04:00
d57c1e7ff0 revert prerender changes and change default 2024-05-10 16:28:19 -04:00
13e97703e5 Merge pull request #4244 from sbwalker/dev
modify prerendering UI options
2024-05-09 15:09:07 -04:00
c597b293b8 modify prerendering UI options 2024-05-09 15:08:52 -04:00
6620d64ce7 Merge pull request #4243 from sbwalker/dev
add support for Auto Prerendering
2024-05-09 14:43:07 -04:00
2ae120c878 add support for Auto Prerendering 2024-05-09 14:42:54 -04:00
7a25035fb1 Merge pull request #4239 from sbwalker/dev
require AntiForgery on Static Rendered components
2024-05-08 14:42:59 -04:00
bf4052b550 require AntiForgery on Static Rendered components 2024-05-08 14:42:39 -04:00
5ca5ad2cee Merge pull request #4226 from ohba-ikuo/oqtane-#4223
Fix #4223 In the Ubuntu environment, an error occurs when trying to upload a file.
2024-05-07 13:49:25 -04:00
2848f1e13c Merge pull request #4237 from sbwalker/dev
fix #4235 - add space above Logout button in Control Panel
2024-05-07 13:49:14 -04:00
f7895823cb fix #4235 - add space above Logout button in Control Panel 2024-05-07 13:48:58 -04:00
b841c5c5e5 Merge pull request #4234 from sbwalker/dev
add shadow-none to page links in pager
2024-05-06 15:56:20 -04:00
a7952a4633 add shadow-none to page links in pager 2024-05-06 15:56:05 -04:00
d047d26dbf Reverted and fixed the source code. 2024-05-05 12:12:40 +09:00
ddedc1640f Merge pull request #4227 from sbwalker/dev
fix #4221 - exception in Module Management when a module has been uninstalled (credit @marceloatoledo)
2024-05-03 13:37:29 -04:00
021d7e5efc fix #4221 - exception in Module Management when a module has been uninstalled (credit @marceloatoledo) 2024-05-03 13:37:10 -04:00
332e528012 Fix #4223 2024-05-03 21:18:28 +09:00
a0155da06b Merge pull request #4219 from mdmontesinos/dev
[ENH] Support for IconOnly in ActionDialog open button
2024-05-02 07:45:06 -04:00
d58d22adbe Merge pull request #4218 from leigh-pointer/CheckNullString
Null or empty check for FormatContent
2024-05-02 07:43:39 -04:00
653352bff0 Support for IconOnly in ActionDialog open button 2024-05-02 10:36:29 +02:00
4f5b33d8df Null or empty check for FormatContent
Added null or empty check for the content and alias parameters at the beginning of the method.
2024-05-02 09:03:26 +02:00
7e7d83ac36 Merge pull request #4217 from sbwalker/dev
fix support for Site-level Scripts in Resources
2024-05-01 15:18:51 -04:00
0de5c043bb fix support for Site-level Scripts in Resources 2024-05-01 15:18:36 -04:00
ec2769ea3c Merge pull request #4215 from sbwalker/dev
fix RESX file (add missing element)
2024-05-01 11:52:22 -04:00
3f742f5f8e fix RESX file (add missing element) 2024-05-01 11:52:07 -04:00
50849101d4 Merge pull request #4208 from iJungleboy/patch-1
Update README.md, move history to docs
2024-05-01 11:49:23 -04:00
1ccf4a74c9 Merge pull request #4214 from leigh-pointer/TranslateModuleSettingsTitle
ModuleSettings Title Localized
2024-05-01 11:49:08 -04:00
7cd4967963 Merge pull request #4205 from leigh-pointer/MissingParams
Fix for missing parameters and Resx values Issue #4202 #4203 #4210 and part #4209
2024-05-01 11:47:11 -04:00
21e2700da5 ModuleSettings Title Localized 2024-05-01 08:33:51 +02:00
395a68ad80 Merge branch 'dev' into MissingParams 2024-05-01 08:20:29 +02:00
b7f0132675 Merge pull request #4213 from sbwalker/dev
fix #4206 - validate folder name for duplicates
2024-04-30 16:41:37 -04:00
4ac827b9e8 fix #4206 - validate folder name for duplicates 2024-04-30 16:41:24 -04:00
d96963862e Merge pull request #4212 from leigh-pointer/ModuleContainerSettingsTrans
ModuleSettings ContainerSettings #4211
2024-04-30 16:19:28 -04:00
53217b061d ModuleSettings ContainerSettings #4211
ModuleSettings ContainerSettings #4211
2024-04-30 20:07:34 +02:00
4770daa7c6 Fix for Issue #4210 and part #4209
This I will work on on a  different Issue
2024-04-30 19:46:10 +02:00
2b709ad094 Update README.md, move history to docs
moved release history and old announcements to the docs
2024-04-30 13:14:58 +02:00
378b81b13b Fix for missing parameters and Resx values
Issue #4202 Issue #4203
2024-04-30 08:17:53 +02:00
56ee72214f Merge pull request #4204 from sbwalker/dev
refactor #4198 - copy existing module
2024-04-29 15:01:12 -04:00
2e7c3167f5 refactor #4198 - copy existing module 2024-04-29 14:58:30 -04:00
a2fb728d3b Merge pull request #4198 from zyhfish/task/fix-issue-4030
Fix #4030: add copy module option for add existing module function.
2024-04-29 13:38:34 -04:00
Ben
be1c936e90 Fix #4030: move copy option to the add module dropdown. 2024-04-29 22:04:01 +08:00
af8037ab03 Merge pull request #4201 from sbwalker/dev
allow hidden pages to be included in SiteMap
2024-04-29 08:58:38 -04:00
3b8dc98226 allow hidden pages to be included in SiteMap 2024-04-29 08:58:20 -04:00
Ben
b411b4e61b display error message for different action. 2024-04-27 19:32:07 +08:00
Ben
436eb30490 Fix #4030: add copy module option for add existing module function. 2024-04-27 12:32:31 +08:00
09b8087787 Merge pull request #4194 from ijaz-saeed/dev
Format Exception in int.Parse(route.ModuleId)
2024-04-26 13:26:02 -04:00
4ac4c69820 Merge pull request #4195 from zyhfish/task/fix-language-switch-redirect-issue
avoid redirect to home page when switching language.
2024-04-26 13:25:48 -04:00
3ebc5c0865 Merge pull request #4197 from sbwalker/dev
add support for Library modules and optimize usage of reflection during startup
2024-04-26 13:23:17 -04:00
7b94f8f105 add support for Library modules and optimize usage of reflection during startup 2024-04-26 13:22:56 -04:00
Ben
ec994b3e97 avoid redirect to home page when switching language. 2024-04-25 23:18:17 +08:00
86ae0182fd Format Exception in int.Parse(route.ModuleId)
int.Parse("-1") throws  FormatException for cultures other than
 English (en-US)
2024-04-25 19:30:24 +05:00
bfa891f0ca Merge pull request #4193 from leigh-pointer/LangButtStyle
LanguageSwitcher to use the ButtonClass parameter
2024-04-25 08:22:19 -04:00
ef843cac63 LanguageSwitcher to use the ButtonClass parameter
This change allows the buttons to be uniform.
2024-04-25 12:33:52 +02:00
78d68d0a4f Merge pull request #4190 from sbwalker/dev
fix #4186 - enable language switcher in static render mode
2024-04-24 15:55:16 -04:00
4bceba777d fix #4186 - enable language switcher in static render mode 2024-04-24 15:55:00 -04:00
2e537b1e5e Merge pull request #4189 from sbwalker/dev
fix HTML comment to indicate actual RenderMode for component (including Interactivity)
2024-04-24 13:23:54 -04:00
df8463b625 fix HTML comment to indicate actual RenderMode for component (including Interactivity) 2024-04-24 13:22:28 -04:00
f40371e0cf Update README.md 2024-04-24 10:04:10 -04:00
a565e7aed6 Merge pull request #4188 from sbwalker/dev
minor refactoring of #4179
2024-04-24 09:49:08 -04:00
c948361090 minor refactoring of #4179 2024-04-24 09:48:51 -04:00
4cf2b74a01 Merge pull request #4179 from LearnOqtane/dev
[ENH] - Add Prerender IModuleControl property (similar to RenderMode)…
2024-04-24 09:32:11 -04:00
de9c8362ac [ENH] - #4178 simplified version with null-coalescing operator ?? 2024-04-24 10:13:46 +10:00
b5bb5d35e7 [ENH] - #4178 correcting logic error 2024-04-24 09:49:07 +10:00
d910cfa919 [ENH] - #4178 modifications after review 2024-04-24 09:46:07 +10:00
5857e3d5c6 Merge branch 'oqtane:dev' into dev 2024-04-24 06:36:47 +10:00
25daa343c6 Merge pull request #4184 from leigh-pointer/ParamsLang
Parameters Missing fix for #4180 #4182
2024-04-23 14:10:43 -04:00
85224c8f0c Merge pull request #4185 from sbwalker/dev
fix #4160 - content entered being overidden by original content
2024-04-23 14:05:02 -04:00
5f8583e3eb fix #4160 - content entered being overidden by original content 2024-04-23 14:04:52 -04:00
062821d267 Parameters Missing fix for #4180 #4182 2024-04-23 19:45:13 +02:00
1fdaaf82d2 Merge pull request #4169 from leigh-pointer/Bug4168
Fix for #4168 #4170 missing Translations
2024-04-23 13:19:24 -04:00
e4c1b17810 Merge pull request #4183 from sbwalker/dev
fix path issue for root page
2024-04-23 13:15:55 -04:00
70057542c1 fix path issue for root page 2024-04-23 13:15:44 -04:00
f2255ee707 Merge pull request #4181 from sbwalker/dev
replace form with link in AdminContainer
2024-04-23 12:54:56 -04:00
791cc70b09 replace form with link in AdminContainer 2024-04-23 12:54:44 -04:00
24dcb9973b Merge pull request #4164 from ohba-ikuo/add-ohba-ikuo
Datetime formatting issue
2024-04-23 08:45:58 -04:00
adfd0d5c18 Fix MicroService And Controller 2024-04-23 21:27:13 +09:00
cfb128acb8 [ENH] - Add Prerender IModuleControl property (similar to RenderMode) #4178 2024-04-23 15:22:02 +10:00
1e8e246ffb Merge pull request #4177 from sbwalker/dev
fix #4165 - missing slash in subfolder sites
2024-04-22 17:09:31 -04:00
6162244730 fix #4165 - missing slash in subfolder sites 2024-04-22 17:09:18 -04:00
86cbdf2442 Merge pull request #4161 from zyhfish/task/fix-issue-4158
Fix #4158: insert image into correct position.
2024-04-22 16:28:47 -04:00
5334626efb Merge pull request #4167 from leigh-pointer/ExtraTDinTheme
Rogue TD in table
2024-04-22 16:16:30 -04:00
708d473b47 Missing Parameter
#4176
2024-04-22 20:19:33 +02:00
ead954ddaa Missing Parameters
#4174 #4175
2024-04-22 19:18:02 +02:00
294f511b9a Missing parameters
#4172 #4173
2024-04-22 18:27:01 +02:00
b5ebcc3e07 Update Index.razor 2024-04-22 17:46:13 +02:00
7b8e7ac5c2 Fix for #4168
Resx entry for Module Settings Permissions tab
2024-04-22 17:14:09 +02:00
904d39beac Rouge TD in table
Deleted a rouge TD in the themes index table
2024-04-22 14:08:09 +02:00
8958b61fdd Datetime formatting issue 2024-04-21 20:44:41 +09:00
Ben
09293f7d9a Fix #4158: insert image into correct position. 2024-04-20 16:56:32 +08:00
d520c3d674 Merge pull request #4157 from sbwalker/dev
fix #4150 - remove Add Existing Module option when managing personalized pages
2024-04-18 18:43:43 -04:00
430e616328 fix #4150 - remove Add Existing Module option when managing personalized pages 2024-04-18 18:43:14 -04:00
976ad5fcee Update README.md 2024-04-16 13:47:24 -04:00
4d58ee2162 Update README.md 2024-04-16 13:46:55 -04:00
03b6abe5ec Merge pull request #4149 from oqtane/master
5.1.1 release
2024-04-16 13:34:15 -04:00
4479304f3f Merge pull request #4148 from oqtane/dev
5.1.1 release
2024-04-16 13:33:51 -04:00
ed83405254 Merge pull request #4147 from sbwalker/dev
fix SiteMap path issue
2024-04-16 13:04:39 -04:00
b815d945d9 fix SiteMap path issue 2024-04-16 13:04:25 -04:00
2b8e024f48 Merge pull request #4146 from sbwalker/dev
include .NET MAUI CORS policy for static files
2024-04-16 12:36:53 -04:00
2a0399b98d include .NET MAUI CORS policy for static files, add support for [wwwroot] in content 2024-04-16 12:36:31 -04:00
4e333e2d75 Merge pull request #4145 from sbwalker/dev
fix SiteRouter issue when running on .NET MAUI
2024-04-16 08:03:16 -04:00
4f25b7bbbe fix SiteRouter issue when running on .NET MAUI 2024-04-16 08:02:59 -04:00
3678db649b Merge pull request #4144 from sbwalker/dev
fixes for #4134 - Rich Text Editor
2024-04-15 08:54:30 -04:00
9d8b1fd99b fixes for #4134 - Rich Text Editor 2024-04-15 08:54:23 -04:00
7b62c06be3 Merge pull request #4140 from sbwalker/dev
convert Quill's empty content to empty string
2024-04-12 15:11:01 -04:00
bc978a91e3 convert Quill's empty content to empty string 2024-04-12 15:10:47 -04:00
611ba97b60 Merge pull request #4139 from sbwalker/dev
more changes for #4134 - ensure HTML content is preserved
2024-04-12 14:58:27 -04:00
39dff1ea7c more changes for #4134 - ensure HTML content is preserved 2024-04-12 14:58:14 -04:00
bcf7bcba1d Merge pull request #4137 from sbwalker/dev
fix #4134 - RichTextEditor scenarios
2024-04-12 13:25:59 -04:00
8f00730189 fix #4134 - RichTextEditor scenarios 2024-04-12 13:25:44 -04:00
1dde79ace2 Merge pull request #4136 from zyhfish/bug/fix-issue-4121
Fix #4121: avoid nested square bracket issue.
2024-04-12 11:04:25 -04:00
Ben
5954fb91be Fix #4121: avoid nested square bracket issue. 2024-04-12 21:56:49 +08:00
e192383662 Merge pull request #4135 from leigh-pointer/TokenRep
InitializeTokenReplace not setting the correct PackageReference
2024-04-12 07:41:40 -04:00
4a20fad4e5 InitializeTokenReplace not setting the correct PackageReference
For completeness.
2024-04-12 12:21:44 +02:00
a469e0864e Merge pull request #4132 from sbwalker/dev
move RichTextEditor script registration to Body
2024-04-11 15:27:09 -04:00
cfce2bdbd9 move RichTextEditor script registration to Body 2024-04-11 15:26:55 -04:00
529b5c0a00 Merge pull request #4130 from sbwalker/dev
prepare for 5.1.1 release
2024-04-11 14:28:12 -04:00
7cc5787779 prepare for 5.1.1 release 2024-04-11 14:27:59 -04:00
48eeb279e2 Merge pull request #4129 from sbwalker/dev
add Process info to System Info to indicate if process is 32 bit or 64 bit
2024-04-11 13:34:25 -04:00
d67566252a add Process info to System Info to indicate if process is 32 bit or 64 bit 2024-04-11 13:34:06 -04:00
8a2d79e17d Merge pull request #4127 from sbwalker/dev
fix issue where active tab not set correctly when rich text editor disabled
2024-04-11 09:16:57 -04:00
17370dff54 fix issue where active tab not set correctly when rich text editor disabled 2024-04-11 09:16:39 -04:00
f08a8e7634 Merge pull request #4126 from sbwalker/dev
fix https://github.com/oqtane/oqtane.blogs/issues/44 - rich text editor throwing exception in specific scenario
2024-04-11 09:04:00 -04:00
83543bbddc fix https://github.com/oqtane/oqtane.blogs/issues/44 - rich text editor throwing exception in specific scenario 2024-04-11 09:03:41 -04:00
b898c90f41 Merge pull request #4125 from leigh-pointer/ImageSharpUpdate
ImageSharp update from 3.1.3 to 3.1.4
2024-04-11 07:44:51 -04:00
1ec927cf4f ImageSharp update from 3.1.3 to 3.1.4 2024-04-11 11:11:05 +02:00
aef21ba9d5 Merge pull request #4124 from sbwalker/dev
update theme and module templates to .NET SDK 8.0.4
2024-04-10 16:29:35 -04:00
0b31709aee update theme and module templates to .NEt SDK 8.0.4 2024-04-10 16:29:16 -04:00
7c3433256a Merge pull request #4123 from sbwalker/dev
update to .NET SDK 8.0.4
2024-04-10 16:24:40 -04:00
c79c638f35 update to .NET SDK 8.0.4 2024-04-10 16:24:23 -04:00
a148941a39 Merge pull request #4119 from sbwalker/dev
fix #4109 - fix resx key in SqlServerConfig (credit @mmisu)
2024-04-09 08:06:31 -04:00
23abe26b0b fix #4109 - fix resx key in SqlServerConfig (credit @mmisu) 2024-04-09 08:06:12 -04:00
8f21d6dde0 Merge pull request #4112 from mdmontesinos/dev
fix #4103 - Visual Studio build acceleration breaks Oqtane Module build process
2024-04-08 14:32:09 -04:00
b74a6c9e03 Merge pull request #4118 from sbwalker/dev
removing StreamRendering attribute as recent SDK seems to have resolved earlier rendering issues
2024-04-08 14:31:52 -04:00
b63f73ef93 removing StreamRendering attribute as recent SDK seems to have resolved earlier rendering issues 2024-04-08 14:31:12 -04:00
1f0b369a15 Disable Accelerate Builds for Package project in Module template 2024-04-06 08:37:48 +02:00
7a43473513 Disable Accelerate Builds for Package project in Theme template 2024-04-06 08:36:13 +02:00
07f367a2a5 Merge pull request #4111 from sbwalker/dev
fix #4108 - content lost when adding image to RichTextEditor
2024-04-05 16:07:15 -04:00
c52ad68d92 fix #4108 - content lost when adding image to RichTextEditor 2024-04-05 16:07:01 -04:00
85467dbd2a Merge pull request #4106 from sbwalker/dev
update text in component to be consistent with resx
2024-04-04 12:01:01 -04:00
aa767846f0 update text in component to be consistent with resx 2024-04-04 12:00:52 -04:00
6d3ad15d20 Merge pull request #4105 from sbwalker/dev
modify #4099 - fix localization and use Delete rather than Clear in API methods for consistency with rest of framework
2024-04-04 11:58:22 -04:00
7b95db4d13 modify #4099 - fix localization and use Delete rather than Clear in API methods for consistency with rest of framework 2024-04-04 11:58:05 -04:00
160b3ff655 Merge pull request #4099 from zyhfish/task/fix-3625
Fix #3625: add the clear logs function.
2024-04-04 08:26:41 -04:00
Ben
757a39a75e update code by review result. 2024-04-03 22:27:39 +08:00
Ben
4c08a527be Fix #3625: add the clear logs function. 2024-04-03 09:21:13 +08:00
578b7b0512 Update issue templates 2024-04-02 16:43:43 -04:00
45e0259099 Update issue templates 2024-04-02 16:41:52 -04:00
1ac1933ec1 Update issue templates 2024-04-02 16:37:54 -04:00
43353e89bb Merge pull request #4098 from sbwalker/dev
fix ThemeSettings SetSetting() references to not specify IsPrivate property
2024-04-02 10:53:24 -04:00
010e4610f7 fix ThemeSettings SetSetting() references to not specify IsPrivate property 2024-04-02 10:53:07 -04:00
ba38853406 Merge pull request #4097 from sbwalker/dev
fix SiteMap so that it supports page Urls
2024-04-02 08:45:03 -04:00
4944a9e51e fix SiteMap so that it supports page Urls 2024-04-02 08:44:51 -04:00
73ad97859c Merge pull request #4093 from sbwalker/dev
fix #4091 - double slash generated for home page path ("/") and urlparameters
2024-04-01 15:11:38 -04:00
e600da229c fix #4091 - double slash generated for home page path ("/") and urlparameters 2024-04-01 15:11:20 -04:00
273b4f20db Merge pull request #4090 from sbwalker/dev
fix #4088 - redirect to login if not authenticated
2024-04-01 12:01:04 -04:00
9843dccdf0 fix #4088 - redirect to login if not authenticated 2024-04-01 12:00:53 -04:00
60ae1ec1e8 Merge pull request #4089 from W6HBR/dev
Fix incorrect parameter passed from ProfileService to ProfileController
2024-04-01 09:53:48 -04:00
650c6670f2 Fix incorrect parameter passed from ProfileService.cs to ProfileController.cs
ProfileService was passing SiteId instead of ProfileId which was causing updates to profile entries to fail with "Unauthorized Profile Put Attempt".
2024-03-31 10:08:19 -07:00
d6dcba7a60 Merge pull request #4083 from sbwalker/dev
use Constants.RequestVerificationToken rather than magic string
2024-03-29 11:19:33 -04:00
5b3849082f use Constants.RequestVerificationToken rather than magic string 2024-03-29 11:19:21 -04:00
5de988a2e6 Merge pull request #4082 from sbwalker/dev
remove changes to allow path to support urls - urls should be specified as redirects
2024-03-29 10:15:42 -04:00
26220b2f54 remove changes to allow path to support urls - urls should be specified as redirects 2024-03-29 10:15:24 -04:00
8d8436f1f1 Merge pull request #4081 from sbwalker/dev
set active tab correctly in RichTextEditor for scenarios where rich text editor is disabled
2024-03-29 07:50:27 -04:00
93057d9449 set active tab correctly in RichTextEditor for scenarios where rich text editor is disabled 2024-03-29 07:50:03 -04:00
2addcc3ab5 Merge branch 'dev' of https://github.com/Trifoia/oqtane.framework into dev 2024-03-28 13:47:43 -07:00
b2419abdc8 Merge pull request #4079 from sbwalker/dev
fix #4073 - OIDC/OAuth2 flow with static rendering
2024-03-28 16:12:15 -04:00
9f654918ae fix #4073 - OIDC/OAuth2 flow with static rendering 2024-03-28 16:12:02 -04:00
cb086fe08d Merge pull request #4077 from zyhfish/task/fix-issue-4074
Fix #4074: use the correct property value.
2024-03-28 14:23:46 -04:00
1482166ba3 Merge pull request #4078 from sbwalker/dev
fix #4075 - auth cookie being rejected under some scenarios - change from Strict to Lax to match latest .NET Identity configuration
2024-03-28 14:23:31 -04:00
6b8dd9bf03 fix #4075 - auth cookie being rejected under some scenarios - change from Strict to Lax to match latest .NET Identity configuration 2024-03-28 14:23:13 -04:00
Ben
a8af9da249 Fix #4074: use the correct property value. 2024-03-28 22:18:30 +08:00
e410f82fdb Update README.md 2024-03-27 15:01:47 -04:00
4f70f228f1 Update README.md 2024-03-27 10:43:55 -04:00
ddc97b99fa Update README.md 2024-03-27 10:37:03 -04:00
5f42918cc9 Update README.md 2024-03-27 10:09:39 -04:00
e6dfe6fe89 Update README.md 2024-03-27 08:57:52 -04:00
fdbe693139 Merge pull request #4070 from oqtane/master
5.1.0 release
2024-03-27 08:44:22 -04:00
0633b2876c Merge pull request #4069 from oqtane/dev
5.1.0 release
2024-03-27 08:43:57 -04:00
ee45ed8ec2 Merge pull request #4068 from sbwalker/dev
fix upgrade issue by removing legacy Views assembly
2024-03-26 14:27:06 -04:00
0c6726e3f7 fix upgrade issue by removing legacy Views assembly 2024-03-26 14:26:55 -04:00
2a75995189 Merge pull request #4067 from zyhfish/task/fix-issue-4066
Fix #4066: set the RenderModeBoundary instance.
2024-03-26 13:39:11 -04:00
Ben
9f074c1ab7 Fix #4066: set the RenderModeBoundary instance. 2024-03-26 22:48:55 +08:00
2917ee3b9d Merge pull request #4065 from leigh-pointer/UpdateTemplateJson
Updated Template Module and Theme json from 5.0.0 to 5.1.0
2024-03-26 07:21:03 -04:00
03f631f537 Updated Template Module and Theme json from 5.0.0 to 5.1.0 2024-03-26 11:53:49 +01:00
fb4171ae6f Merge pull request #4064 from thabaum/Fixes-#4062-move-app-body-resources
Fixes #4062: App.razor - moves loading body resources above blazor.web.js
2024-03-25 14:27:38 -04:00
aec7d5aff7 moves loading body resources above blazor.web.js 2024-03-25 11:04:14 -07:00
045c225c8c Merge pull request #4063 from sbwalker/dev
fix #4061 - invalid type for favicon
2024-03-25 13:05:32 -04:00
c49ef49371 fix #4061 - invalid type for favicon 2024-03-25 13:05:20 -04:00
9fd012229b Merge pull request #4060 from sbwalker/dev
increase minimum characters to view Edit button at bottom
2024-03-25 07:41:02 -04:00
bb27099f9e increase minimum characters to view Edit button at bottom 2024-03-25 07:40:48 -04:00
411634ecda Merge pull request #4056 from sbwalker/dev
set active tab in RichTextEditor based on content
2024-03-23 11:55:56 -04:00
bb59f66008 set active tab in RichTextEditor based on content 2024-03-23 11:55:44 -04:00
b8a0f34c33 Merge pull request #4055 from sbwalker/dev
fix regression issue caused by #3985 related to ActionLink
2024-03-23 11:39:24 -04:00
784955cdbd fix regression issue caused by #3985 related to ActionLink 2024-03-23 11:39:11 -04:00
83764ce3d5 Merge pull request #4054 from sbwalker/dev
move Html/Text Edit button to top of content
2024-03-23 11:12:24 -04:00
438cf271c0 move Html/Text Edit button to top of content 2024-03-23 11:12:05 -04:00
8631eacdf3 Merge pull request #4052 from zyhfish/task/fix-issue-4051
Fix #4051: set the return url correctly.
2024-03-23 11:00:24 -04:00
6e7ce10585 Merge pull request #4053 from sbwalker/dev
optimize SiteRouter to only call SyncService for Interactive render mode
2024-03-23 10:57:55 -04:00
3d4a58cb96 optimize SiteRouter to only call SyncService for Interactive render mode 2024-03-23 10:57:43 -04:00
Ben
6fde3f8453 Fix #4051: set the return url correctly. 2024-03-23 21:47:27 +08:00
016d2f7ab1 Merge pull request #4049 from sbwalker/dev
fix theme template release.,cmd to copy package to /Packages folder
2024-03-22 15:32:09 -04:00
a8ffc414fe fix theme template release.,cmd to copy package to /Packages folder 2024-03-22 15:31:55 -04:00
b0c1c6e880 Merge pull request #4047 from sbwalker/dev
refactoring of #4027
2024-03-21 18:44:28 -04:00
d3e6177a2b refactoring of #4027 2024-03-21 18:44:16 -04:00
8adbdcc675 Merge pull request #4027 from zyhfish/task/fix-issue-4025
Fix #4025: add user setting to keep the view mode.
2024-03-21 15:35:10 -04:00
d1d7ff0d0a Merge pull request #4046 from sbwalker/dev
use consistent naming in SiteRepository
2024-03-21 15:32:39 -04:00
4b05a49b46 use consistent naming in SiteRepository 2024-03-21 15:32:25 -04:00
0309a866c8 Merge pull request #4045 from sbwalker/dev
use DbContextFactory in all Html/Text methods
2024-03-21 15:25:30 -04:00
bbc77f81ca use DbContextFactory in all Html/Text methods 2024-03-21 15:25:17 -04:00
483f6f2188 Merge pull request #4044 from sbwalker/dev
move logging from Html/Text controller to Server Service class so that is captured in all render modes
2024-03-21 15:19:47 -04:00
e0ef3ca39a move logging from Html/Text controller to Server Service class so that is captured in all render modes 2024-03-21 15:19:30 -04:00
aef29ff6c5 Merge pull request #4043 from sbwalker/dev
ignore Antiforgerytoken in logout as it can sometimes prevent a user from logging out unless they refresh their browser, due to the Antiforgerytoken being expired.
2024-03-21 15:03:10 -04:00
ec7bd8c1c8 ignore Antiforgerytoken in logout as it can sometimes prevent a user from logging out unless they refresh their browser, due to the Antiforgerytoken being expired. 2024-03-21 15:02:50 -04:00
fe0d69739d Merge pull request #4042 from sbwalker/dev
updates to module template for static rendering (ActionDialog Id property, Service interface moved to Shared, Client Service using IHttpClientFactory, Async methods added to Repository, Server Service implementation added, Controller uses Server Service implementation, Server Service registered in Startup)
2024-03-21 14:55:31 -04:00
448e3a4639 updates to module template for static rendering (ActionDialog Id property, Service interface moved to Shared, Client Service using IHttpClientFactory, Async methods added to Repository, Server Service implementation added, Controller uses Server Service implementation, Server Service registered in Startup) 2024-03-21 14:55:07 -04:00
2e74d6f652 Merge pull request #4041 from sbwalker/dev
update Theme template tp .NET 8.0.3
2024-03-21 11:45:39 -04:00
237108a6d1 update Theme template tp .NET 8.0.3 2024-03-21 11:45:26 -04:00
ed3a222ed4 Merge pull request #4040 from sbwalker/dev
additional documentation
2024-03-21 10:51:15 -04:00
8a696f6c52 additional documentation 2024-03-21 10:51:03 -04:00
184aa4fd20 Merge pull request #4039 from sbwalker/dev
add HttpClientFactory support
2024-03-21 10:43:59 -04:00
ce14b9e43e add HttpClientFactory support 2024-03-21 10:43:46 -04:00
1cdedb89f1 Merge pull request #4029 from zyhfish/task/fix-issue-4028
Fix #4028: check whether the user info is null.
2024-03-21 07:56:49 -04:00
Ben
18efb098f9 remove unused variables. 2024-03-21 08:39:55 +08:00
Ben
fb3a27c02f update the code by following the review suggestions. 2024-03-21 08:38:59 +08:00
Ben
6d41bcd511 update the if condition. 2024-03-21 08:17:45 +08:00
e6b981fc38 Merge pull request #4034 from thabaum/module-creator-package-803
Fixes #4033: Updates Module creator template package references to 8.0.3
2024-03-20 14:54:22 -04:00
74a3ea2a01 Update package references to 8.0.3 2024-03-20 11:31:19 -07:00
4bfb7a5d29 Updates package dependencies to 8.0.3 2024-03-20 11:29:45 -07:00
55ba040e3d Merge pull request #4032 from sbwalker/dev
fix #4031 - add static rendering support to ActionDialog
2024-03-20 13:26:02 -04:00
e4e78e2083 fix #4031 - add static rendering support to ActionDialog 2024-03-20 13:25:51 -04:00
Ben
82f25cc2e5 Fix #4028: check whether the user info is null. 2024-03-20 16:32:51 +08:00
Ben
7b67c9aa8d Fix #4025: add user setting to keep the view mode. 2024-03-20 15:46:32 +08:00
854f3b5257 Merge pull request #4021 from sbwalker/dev
fix #4020 - EditUrl contains extra slash on child sites
2024-03-19 14:16:50 -04:00
e37bc99c36 fix #4020 - EditUrl contains extra slash on child sites 2024-03-19 14:16:37 -04:00
52121b90ff Merge pull request #4019 from sbwalker/dev
fix #4017 - SiteState being lost in server rendered scenarios
2024-03-19 13:53:26 -04:00
3eb9de57ef fix #4017 - SiteState being lost in server rendered scenarios 2024-03-19 13:53:05 -04:00
4ed501f4d4 Merge pull request #4018 from sbwalker/dev
pass RenderModeBoundary parameter when dynamically creating Module Settings component
2024-03-19 10:19:55 -04:00
0bb8ae540d pass RenderModeBoundary parameter when dynamically creating Module Settings component 2024-03-19 10:19:31 -04:00
963957f7a6 Merge pull request #4016 from sbwalker/dev
fix #4015 - handle redirect for subfolder aliases
2024-03-19 07:40:25 -04:00
93a152068d fix #4015 - handle redirect for subfolder aliases 2024-03-19 07:40:08 -04:00
bb318aefd2 Merge pull request #4011 from zyhfish/task/update-tenant-db-context
Fix #4010: update repositories to using db context factory.
2024-03-18 22:29:27 -04:00
Ben
0cafef7ab4 update to load the data in scope. 2024-03-19 09:19:56 +08:00
Ben
055e54966d upate the code lines. 2024-03-18 21:41:59 +08:00
Ben
c58254f951 Fix #4010: update repositories to using db context factory. 2024-03-18 15:32:19 +08:00
ce710134ac Merge pull request #4009 from sbwalker/dev
Remove Synchronize Content option from RichTextEditor
2024-03-17 19:30:55 -04:00
fa68bdc82b Remove Synchronize Content option from RichTextEditor 2024-03-17 19:30:42 -04:00
cd9f2ab232 Merge pull request #4006 from zyhfish/task/fix-issue-3977-new 2024-03-17 14:08:23 -04:00
Ben
91136fe48f Fix #3977: missed readonly attribute. 2024-03-17 22:01:27 +08:00
Ben
40cc0f721d Fix #3977: use db context factory. 2024-03-17 21:29:32 +08:00
72567c43e6 Merge pull request #4003 from zyhfish/task/fix-issue-4002
Fix #4002: add the quill editor js map file.
2024-03-16 16:25:31 -04:00
db82d7a6b3 Merge pull request #4004 from sbwalker/dev
optimize to remove IsInstalled API call on every Web UI request (MAUI clients still require this logic)
2024-03-16 16:24:38 -04:00
c469a61908 optimize to remove IsInstalled API call on every Web UI request (MAUI clients still require this logic) 2024-03-16 16:24:12 -04:00
Ben
1c4bcc5697 Fix #4002: add the quill editor js map file. 2024-03-16 20:24:52 +08:00
0f3b0309e8 Merge pull request #4001 from sbwalker/dev
fix #3998 - personalized page display issue
2024-03-15 19:49:49 -07:00
5a393de1cb fix #3998 - personalized page display issue 2024-03-15 22:49:28 -04:00
1617a61b33 Merge pull request #4000 from sbwalker/dev
made Pager capable of functioning in Static or Intreractive render modes
2024-03-15 19:48:02 -07:00
ccd18c4f10 made Pager capable of functioning in Static or Intreractive render modes 2024-03-15 22:47:42 -04:00
e287f5774a Merge pull request #3996 from sbwalker/dev
fix issue referencing ClaimsPrincipal UserId extension method
2024-03-14 20:55:11 -07:00
2dec3195ac fix issue referencing ClaimsPrincipal UserId extension method 2024-03-14 23:55:01 -04:00
2bea6694c7 Merge pull request #3995 from sbwalker/dev
fix #3993 - personalized page throwing 404 on static render mode
2024-03-14 20:15:47 -07:00
38c468a204 fix #3993 - personalized page throwing 404 on static render mode 2024-03-14 23:15:37 -04:00
6a80258163 Merge pull request #3994 from sbwalker/dev
add static pager
2024-03-14 20:13:50 -07:00
55fe2600b7 add static pager 2024-03-14 23:13:40 -04:00
cad4e183c5 Merge pull request #3992 from thabaum/package-dependencies-803
Fix #3991: Updates Package Dependencies In Project Files To Relating Current Versions For 8.0.3 Release
2024-03-14 19:36:52 -07:00
ba447d2b00 Update package references to version 8.0.3 release 2024-03-14 15:02:06 -07:00
fa5e32c46b Update Package References To Version 8.0.3 2024-03-14 14:49:41 -07:00
e51b7c22a6 Update Package Reference Microsoft.EntityFrameworkCore.Relational To Version 8.0.3 2024-03-14 14:47:22 -07:00
0473cdc5e1 Update Microsoft.EntityFrameworkCore.Sqlite package reference version to 8.0.3 2024-03-14 14:45:57 -07:00
36c65e8b5f Update Microsoft.EntityFrameworkCore.SqlServer to version 8.0.3 2024-03-14 14:44:24 -07:00
d0e81b7778 Update Oqtane.Server.csproj package references to 8.0.3 2024-03-14 14:42:37 -07:00
7df63c87c9 Update Oqtane.Shared.csproj package references. 2024-03-14 14:38:53 -07:00
0021f7b4ba Merge pull request #3985 from leigh-pointer/ActionLink
_text being set and resetting other options
2024-03-13 14:57:20 -07:00
540283970a Merge pull request #3986 from sbwalker/dev
fix #3984 - error when file path not specified
2024-03-13 14:54:43 -07:00
5a2b9b60e6 fix #3984 - error when file path not specified 2024-03-13 17:54:25 -04:00
12e09269d3 _text being set and resetting other options
if (IconOnly && !string.IsNullOrEmpty(IconName)) was not having an impact as the _text variable was being reset.

This fix allows the ActionLink to display just the Icon
2024-03-13 14:39:04 +01:00
bcad5eda81 Merge pull request #3981 from mdmontesinos/dev
Update Module Template IServerStartup to be ServerStartup instead of DbContextFactory
2024-03-12 10:29:47 -04:00
09ad56056e Merge pull request #3982 from sbwalker/dev
improve caching for sites with many registered users
2024-03-12 10:27:55 -04:00
0c8dc63085 improve caching for sites with many registered users 2024-03-12 10:27:32 -04:00
68e3bcba05 Remove previous [Module]DbContextFactory.cs 2024-03-12 11:40:21 +01:00
75a6111a9b Add [Module]ServerStartup.cs to Module Template 2024-03-12 11:39:45 +01:00
1d9f970169 Merge pull request #3979 from sbwalker/dev
stay in Edit Mode when editing Module Settings
2024-03-11 13:10:35 -04:00
7cc328ed3b stay in Edit Mode when editing Module Settings 2024-03-11 13:10:21 -04:00
9a1c88c80d Merge pull request #3978 from sbwalker/dev
fix #3947 - module deletion
2024-03-11 12:37:03 -04:00
b1446438fb fix #3947 - module deletion 2024-03-11 12:36:51 -04:00
6ba1d71a81 Merge pull request #3973 from sbwalker/dev
site router optimization
2024-03-10 13:37:30 -04:00
a4f885a2c5 site router optimization 2024-03-10 13:37:05 -04:00
a8a3c63f64 Merge pull request #3972 from sbwalker/dev
fix resource processing issue
2024-03-10 09:18:28 -04:00
ace7b4e2af fix resource processing issue 2024-03-10 09:17:54 -04:00
a2885a90b7 Merge pull request #3971 from sbwalker/dev
use IServerStartup rather than class naming convention to register server service class
2024-03-09 07:54:27 -05:00
4457487e2a use IServerStartup rather than class naming convention to register server service class 2024-03-09 07:53:58 -05:00
830bb5f70d Merge pull request #3970 from sbwalker/dev
remove commented code
2024-03-08 19:34:28 -05:00
9106f9676c remove commented code 2024-03-08 19:34:15 -05:00
df1690515c Merge pull request #3969 from sbwalker/dev
consolidate Clone logic for Resource objects
2024-03-08 19:33:23 -05:00
8e287da7b5 consolidate Clone logic for Resource objects 2024-03-08 19:33:09 -05:00
128ebe2cb2 Merge pull request #3967 from zyhfish/task/update-template-db-factory
add db factory class into the module template.
2024-03-08 14:04:25 -05:00
404964dfde Merge pull request #3968 from sbwalker/dev
add ability to reload JavaScript on page transitions with enhanced navigation
2024-03-08 14:03:40 -05:00
7f74e79253 add ability to reload JavaScript on page transitions with enhanced navigation 2024-03-08 14:03:22 -05:00
Ben
11b5cc83dc add db factory class into the module template. 2024-03-08 22:44:31 +08:00
bda9d1f8e2 Merge pull request #3966 from sbwalker/dev
updating ImageSharp to latest
2024-03-08 08:20:39 -05:00
32efeee4c7 updating ImageSharp to latest 2024-03-08 08:15:44 -05:00
8adbd90cc3 Merge pull request #3965 from sbwalker/dev
use IServerStartup for registering DbContextFactory
2024-03-08 07:39:47 -05:00
074fcaaa73 use IServerStartup for registering DbContextFactory 2024-03-08 07:39:34 -05:00
d2209c8ead Merge pull request #3964 from sbwalker/dev
fix #3962 - ensure Resource management logic is consistent in App and SiteRouter
2024-03-07 13:02:05 -05:00
31f1079dfa fix #3962 - ensure Resource management logic is consistent in App and SiteRouter 2024-03-07 13:01:46 -05:00
2b87c83fa7 Merge pull request #3961 from sbwalker/dev
use DbContextFactory in SiteRepository
2024-03-06 16:56:38 -05:00
1c31c1947c use DbContextFactory in SiteRepository 2024-03-06 16:56:27 -05:00
50a8a83408 Merge pull request #3960 from sbwalker/dev
stay in edit mode when choosing module action
2024-03-06 14:40:39 -05:00
020fa4eefa stay in edit mode when choosing module action 2024-03-06 14:40:27 -05:00
64cf02bc45 Merge pull request #3959 from sbwalker/dev
use DBContextFactory
2024-03-06 11:37:10 -05:00
06bd964adc use DBContextFactory 2024-03-06 11:36:56 -05:00
2218b7b853 Merge pull request #3958 from sbwalker/dev
register ServerSiteService as Transient
2024-03-05 12:35:28 -05:00
f6c45cd85a register ServerSiteService as Transient 2024-03-05 12:35:17 -05:00
cf4907011b Merge pull request #3957 from sbwalker/dev
fix issue when running .NET MAUI
2024-03-05 12:00:34 -05:00
dea85add5d fix issue when running .NET MAUI 2024-03-05 12:00:23 -05:00
aa3325ef35 Merge pull request #3956 from sbwalker/dev
add IClientService support to .NET MAUI
2024-03-05 11:52:40 -05:00
8059ba7306 add IClientService support to .NET MAUI 2024-03-05 11:52:27 -05:00
c346c4178d Merge pull request #3954 from sbwalker/dev
optimize to use ITransientService rather than introducing a new IServerService interface which needs to be scanned
2024-03-05 10:59:57 -05:00
f2555563a8 optimize to use ITransientService rather than introducing a new IServerService interface which needs to be scanned 2024-03-05 10:59:39 -05:00
b948961d52 Merge pull request #3953 from sbwalker/dev
change IServerService to use Transient rather than Scoped
2024-03-05 10:50:19 -05:00
43987d844f change IServerService to use Transient rather than Scoped 2024-03-05 10:49:50 -05:00
cc3b14dbf8 Merge pull request #3952 from zyhfish/task/fix-pr-3948
Fix #3948: re-render correctly when change progress indicator status.
2024-03-05 10:46:49 -05:00
Ben
3cc2d3260e Fix #3948: re-render correctly when change progress indicator status. 2024-03-05 22:59:55 +08:00
be155f8c6c Merge pull request #3950 from sbwalker/dev
implement client and server service implementations in Html/Text module
2024-03-05 08:44:21 -05:00
74952cf62d implement client and server service implementations in Html/Text module 2024-03-05 08:44:09 -05:00
4a71df7859 Merge pull request #3944 from sbwalker/dev
remove div wrapper in body in Static render mode
2024-03-04 10:30:27 -05:00
7d7ea4c34b remove div wrapper in body in Static render mode 2024-03-04 10:30:09 -05:00
026d22f7f9 Merge pull request #3943 from sbwalker/dev
add data-enhance to edit mode transition
2024-03-04 09:30:28 -05:00
babd351151 add data-enhance to edit mode transition 2024-03-04 09:30:14 -05:00
d11894fd74 Merge pull request #3942 from sbwalker/dev
allow Admin to navigate to login page when signed in
2024-03-04 08:34:29 -05:00
6072eab01d allow Admin to navigate to login page 2024-03-04 08:34:10 -05:00
64e4c77428 Merge pull request #3941 from sbwalker/dev
fix 3937 - url decode before converting to friendly url
2024-03-04 08:24:41 -05:00
48b70d0254 fix 3937 - url decode before converting to friendly url 2024-03-04 08:24:26 -05:00
db2015f826 Merge pull request #3940 from sbwalker/dev
fix #3936 - parent page default when adding new pages
2024-03-04 08:12:57 -05:00
f893cf268b fix #3936 - parent page default when adding new pages 2024-03-04 08:12:40 -05:00
ad12d42b35 Merge pull request #3939 from oqtane/revert-3938-task/fix-pr-3927
Revert "Fix #3927: change to async method to avoid the exception."
2024-03-04 08:11:35 -05:00
63a0c7c10b Revert "Fix #3927: change to async method to avoid the exception." 2024-03-04 08:11:25 -05:00
99d4d5ed9a Merge pull request #3938 from zyhfish/task/fix-pr-3927
Fix #3927: change to async method to avoid the exception.
2024-03-04 07:49:11 -05:00
Ben
7910c28be7 Fix #3927: change to async method to avoid the exception. 2024-03-03 20:09:42 +08:00
32e1ade388 Merge pull request #3931 from leigh-pointer/autocomplete 2024-03-02 11:50:49 -05:00
a8aac7e1b4 Update Pager.razor
Changing the ID had no effect and on further investigation the best way to achieve this is to use the form tag which is a lot stronger implementation.
2024-03-02 17:28:33 +01:00
7404aaf4d2 Merge pull request #3935 from sbwalker/dev
fix #3932 - creating child pages
2024-03-02 09:27:41 -05:00
2f25bd476c fix #3932 - creating child pages 2024-03-02 09:27:24 -05:00
681e4ae7fc Merge pull request #3934 from sbwalker/dev
change resource term
2024-03-02 09:07:24 -05:00
e1ed0d2b09 change resource term 2024-03-02 09:07:04 -05:00
32567a1c66 Merge pull request #3933 from sbwalker/dev
add support specifying RenderMode for Resources
2024-03-02 08:34:43 -05:00
25753af331 add support specifying RenderMode for Resources 2024-03-02 08:34:24 -05:00
6babcf9536 Improved Search Input Text Field Autocomplete Behavior
This pull request enhances the behavior of the search input text field by disabling the browser’s autocomplete feature.
2024-03-02 11:35:26 +01:00
9a05f659f1 Merge pull request #3929 from sbwalker/dev
modifications to ExceptionMiddleware
2024-03-01 16:14:44 -05:00
ca58bf661d modifications to ExceptionMiddleware 2024-03-01 16:14:33 -05:00
62695d4d9a Merge pull request #3925 from pyramidsbuilder/add-exception-middleware
added exception middleware to server for logging
2024-03-01 15:05:35 -05:00
d723ef0a13 Merge pull request #3928 from sbwalker/dev
improvements to IdentityRevalidatingAuthenticationStateProvider
2024-03-01 12:16:39 -05:00
18160818d5 improvements to IdentityRevalidatingAuthenticationStateProvider 2024-03-01 12:16:24 -05:00
83bfaabd95 added exception middleware to server for logging 2024-02-29 23:38:36 +01:00
e23ac8496e Merge pull request #3924 from sbwalker/dev
call JS Interop in Interactive render mode, use PageState.Site.Themes rather than calling ThemeService from Control Panel
2024-02-29 15:38:23 -05:00
2b7d05df6b call JS Interop in Interactive render mode, use PageState.Site.Themes rather than calling ThemeService from Control Panel 2024-02-29 15:38:04 -05:00
606cb249e8 Merge pull request #3923 from sbwalker/dev
set RevalidationInterval to same as default Blazor Web template
2024-02-29 14:48:27 -05:00
0ae739b437 set RevalidationInterval to same as default Blazor Web template 2024-02-29 14:48:14 -05:00
f18e57b50e Merge pull request #3922 from sbwalker/dev
add IdentityRevalidatingAuthenticationStateProvider
2024-02-29 14:47:03 -05:00
4c92c582d7 add IdentityRevalidatingAuthenticationStateProvider 2024-02-29 14:46:50 -05:00
7b1bfeaca1 Merge pull request #3921 from sbwalker/dev
optimize ParseParameters to use native Uri class
2024-02-29 10:09:32 -05:00
dd1d0d1cb8 optimize ParseParameters to use native Uri class 2024-02-29 10:09:19 -05:00
995bd4953b Merge pull request #3920 from thabaum/updates-Microsoft.Data.SqlClient-5.2.0 2024-02-28 23:35:54 -05:00
32b61ac730 Updates Microsoft.Data.SqlClient package reference version to 5.2.0 2024-02-28 20:06:26 -08:00
19bd54f425 Merge pull request #3918 from sbwalker/dev
fix theme fallback to use Oqtane themeinfo resources
2024-02-28 15:53:45 -05:00
76680777ff fix theme fallback to use Oqtane themeinfo resources 2024-02-28 15:53:31 -05:00
75b9a8a826 Merge pull request #3917 from sbwalker/dev
fix page Path so it supports the specification of external Urls, querystrings, and anchors
2024-02-28 13:10:32 -05:00
f439541844 fix page Path so it supports the specification of external Urls, querystrings, and anchors 2024-02-28 13:10:14 -05:00
65fb21a062 Merge pull request #3916 from sbwalker/dev
change Admin Dashboard to use static rendering and fix invalid markup (H2 within P element)
2024-02-28 09:28:23 -05:00
aa5df3c309 change Admin Dashboard to use static rendering and fix invalid markup (H2 within P element) 2024-02-28 09:28:03 -05:00
788394a1c8 Merge pull request #3915 from sbwalker/dev
clean up the data-enhance-nav commented logic in menu components
2024-02-27 17:05:42 -05:00
7286c2f603 remove the data-enhance-nav commented logic in menu components 2024-02-27 17:05:21 -05:00
aff230ec7e Merge pull request #3914 from sbwalker/dev
fix #3868 - multiple themes within a site
2024-02-27 17:02:10 -05:00
3d538d0566 fix #3868 - multiple themes within a site 2024-02-27 17:01:57 -05:00
a1b287bd9d Merge pull request #3912 from sbwalker/dev
reorganize SiteRepository methods
2024-02-27 15:19:38 -05:00
1d187f525d reorganize SiteRepository methods 2024-02-27 15:19:25 -05:00
6c9ab0c019 Merge pull request #3911 from sbwalker/dev
replace Task.Run() logic in SiteService with async SiteRepository methods
2024-02-27 15:13:05 -05:00
e7157a8528 replace Task.Run() logic in SiteService with async SiteRepository methods 2024-02-27 15:12:48 -05:00
e2182344a2 Merge pull request #3910 from zyhfish/task/update-pr-3885
remove the visible parameter in module message component.
2024-02-27 10:24:48 -05:00
Ben
9ebd882c3f remove the visible parameter in module message component. 2024-02-27 23:08:27 +08:00
f017b6b92f Merge pull request #3908 from sbwalker/dev
remove unecessary using
2024-02-27 08:50:01 -05:00
1c24c4e776 remove unecessary using 2024-02-27 08:49:51 -05:00
758e94a8ec Merge pull request #3906 from sbwalker/dev
fix #3885 - do not display modal if message is blank
2024-02-26 16:53:31 -05:00
9a7199bf7f fix #3885 - do not display modal if message is blank 2024-02-26 16:53:17 -05:00
1c691fa2c2 Merge pull request #3905 from sbwalker/dev
fix #3889 - move JavaScript references to end of body
2024-02-26 16:40:12 -05:00
b435f49611 fix #3889 - move JavaScript references to end of body 2024-02-26 16:39:59 -05:00
bcd7b2552e Merge pull request #3904 from sbwalker/dev
Site Setting terminology changes
2024-02-26 16:28:10 -05:00
e76126fdd9 Site Setting terminology changes 2024-02-26 16:27:58 -05:00
3fe55e7395 Merge pull request #3903 from sbwalker/dev
fix prerender helptext
2024-02-26 16:13:50 -05:00
98e11c16fa fix prerender helptext 2024-02-26 16:13:36 -05:00
0c5b2d302b Merge pull request #3902 from sbwalker/dev
improve help text for interactivity
2024-02-26 16:08:58 -05:00
0d526a2c4f improve help text for interactivity 2024-02-26 16:08:44 -05:00
0a8d49c233 Merge pull request #3901 from sbwalker/dev
change default so that new sites use Static rendering by default
2024-02-26 15:59:17 -05:00
4618d3e38a change default so that new sites use Static rendering by default 2024-02-26 15:59:04 -05:00
5521785b87 Merge pull request #3900 from sbwalker/dev
clone Platform property in SiteStte
2024-02-26 14:58:14 -05:00
f12b404d58 clone Platform property in SiteStte 2024-02-26 14:58:01 -05:00
6924e3a7d7 Merge pull request #3899 from sbwalker/dev
refresh cache if user is updated
2024-02-26 14:55:12 -05:00
6fbe459903 refresh cache if user is updated 2024-02-26 14:54:59 -05:00
0a245e5d65 Merge pull request #3898 from sbwalker/dev
include SiteId in SyncEvent
2024-02-26 14:48:39 -05:00
2ed593c5e0 include SiteId in SyncEvent 2024-02-26 14:48:26 -05:00
ce934b8998 Merge pull request #3897 from sbwalker/dev
improve caching for static rendering
2024-02-26 14:28:52 -05:00
aac4d3eefb improve caching for static rendering 2024-02-26 14:28:38 -05:00
176dc17c70 Merge pull request #3896 from sbwalker/dev
add Platform property to SiteState and populate on both Web and .NET MAUI
2024-02-26 14:13:13 -05:00
553bbda769 add Platform property to SiteState and populate on both Web and .NET MAUI 2024-02-26 14:12:52 -05:00
d4fd2d9ae0 Merge pull request #3895 from sbwalker/dev
admin pages url mappings and visitor management isnavigation property should be false for consistency
2024-02-26 11:51:59 -05:00
c20138c9fc admin pages url mappings and visitor management isnavigation property should be false for consistency 2024-02-26 11:51:35 -05:00
7f1ff11a4c Merge pull request #3894 from sbwalker/dev
remove data-enhance from Edit Mode button as it prevents the module actions menu from functioning
2024-02-26 10:57:10 -05:00
ed9121a06f remove data-enhance from Edit Mode button as it prevents the module actions menu from functioning 2024-02-26 10:56:51 -05:00
c110611d82 Merge pull request #3892 from zyhfish/task/revert-pr-3875
Revert "removed AddModuleMessage from OnParametersSetAsync methods to mitigate risk of infinite loops"
2024-02-25 09:33:27 -05:00
Ben
cc222a6f4a Revert "removed AddModuleMessage from OnParametersSetAsync methods to mitigate risk of infinite loops"
This reverts commit 92719d095a.
2024-02-25 08:52:55 +08:00
8293709f34 Merge pull request #3888 from sbwalker/dev
removing fix for #3868 as it causes other performance issues
2024-02-24 10:56:07 -05:00
707740b7f1 removing fix for #3868 as it causes other performance issues 2024-02-24 10:55:44 -05:00
98de661868 Merge pull request #3885 from zyhfish/task/fix-infinite-loop-of-module-message
avoid the infinite loop issue of calling AddModuleMessage method.
2024-02-24 09:56:03 -05:00
64df057e2f Merge pull request #3887 from sbwalker/dev
add data-enhance to AdminContainer to prevent flash when closing modal
2024-02-24 09:32:47 -05:00
9d9c5cff75 add data-enhance to AdminContainer to prevent flash when closing modal 2024-02-24 09:32:29 -05:00
3ed6f360da Merge pull request #3886 from sbwalker/dev
fix #3868 - add data-enhance.nav attribute
2024-02-24 09:09:40 -05:00
9f07f6441a fix #3868 - add data-enhance.nav attribute 2024-02-24 09:09:15 -05:00
Ben
fc0b326443 set the visible default to true. 2024-02-24 22:02:07 +08:00
Ben
4ac0483ec6 Merge branch 'dev' into task/fix-infinite-loop-of-module-message 2024-02-24 20:48:09 +08:00
Ben
724e78d4d5 avoid the infinite loop issue of calling AddModuleMessage method. 2024-02-24 20:45:22 +08:00
6efa0490ea Merge pull request #3883 from sbwalker/dev
organize server RESX files in folders to be consistent with client project
2024-02-23 15:55:47 -05:00
99e032eeb7 organize server RESX files in folders to be consistent with client project 2024-02-23 15:55:31 -05:00
c80c212a54 Merge pull request #3869 from pyramidsbuilder/fix-loginpage-focus-for-ws
handle focus error on blazor web assembly when verifying email address
2024-02-23 15:53:18 -05:00
95460038cf Merge pull request #3821 from pyramidsbuilder/3794-registration-emails-localization
localized usermanager email messages and message formatting to includ…
2024-02-23 15:53:08 -05:00
586e3b891c Merge pull request #3882 from sbwalker/dev
change name of form class to reflect purpose
2024-02-23 14:05:51 -05:00
4402645b37 change name of form class to reflect purpose 2024-02-23 14:05:40 -05:00
42624246bd Merge pull request #3881 from sbwalker/dev
fix #3868 - static rendering support for page themes within site
2024-02-23 09:28:48 -05:00
ddd39ea0c9 fix #3868 - static rendering support for page themes within site 2024-02-23 09:28:33 -05:00
a95cde372c Merge pull request #3880 from leigh-pointer/ThemeRes
Added Resource Files to Theme Templates
2024-02-23 08:00:05 -05:00
dcbf03c355 Added Resource Files to Theme Templates
Currently the template uses the Localization Resource functionality but it will always default to the hardcoded text.  Leaving it to the developer to add the resources could result in a hit and miss scenario. This PR removes the "mis" side.
2024-02-23 13:46:22 +01:00
ce44fb29c9 Merge pull request #3879 from sbwalker/dev
improve UX by adding data-enhance to Edit Mode button
2024-02-23 07:31:24 -05:00
35f5df63e2 improve UX by adding data-enhance to Edit Mode button 2024-02-23 07:31:12 -05:00
60c9200c06 Merge pull request #3877 from sbwalker/dev
remove Microsoft.AspNetCore.Components.WebAssembly.DevServer from default module and theme template as it is no longer needed
2024-02-22 16:41:15 -05:00
25dacccb3b remove Microsoft.AspNetCore.Components.WebAssembly.DevServer from default module and theme template as it is no longer needed 2024-02-22 16:40:55 -05:00
c0d08d966a Merge pull request #3876 from sbwalker/dev
modify ActionLink to use a link rather than button for disabled scenario
2024-02-22 16:35:04 -05:00
cdfae2e8cb modify ActionLink to use a link rather than button for disabled scenario 2024-02-22 16:34:52 -05:00
a3b0c351d0 Merge pull request #3875 from sbwalker/dev
removed AddModuleMessage from OnParametersSetAsync methods to mitigate risk of infinite loops
2024-02-22 14:22:08 -05:00
92719d095a removed AddModuleMessage from OnParametersSetAsync methods to mitigate risk of infinite loops 2024-02-22 14:21:49 -05:00
b2dc397fb0 Merge pull request #3813 from pyramidsbuilder/3805-stop-registration-redirect-without-verification
display verification message instead of redirecting new user before e…
2024-02-22 12:34:21 -05:00
55e09529c1 Merge pull request #3872 from thabaum/update-Oqtane.Server-dependencies
Updates Microsoft.AspNetCore.Authentication.OpenIdConnect To Version 8.0.2
2024-02-22 12:05:30 -05:00
aed91d42bf Merge pull request #3873 from sbwalker/dev
update documentation
2024-02-22 11:02:04 -05:00
eef58f4da0 update documentation 2024-02-22 11:01:49 -05:00
4c427116a8 Update Microsoft.AspNetCore.Authentication.OpenIdConnect To Version 8.0.2 2024-02-22 07:48:58 -08:00
00e9624670 Merge pull request #3870 from thabaum/update-blazor-theme-bootstrap
Updates Blazor Theme Bootstrap to Version 5.3.2
2024-02-22 08:01:15 -05:00
b52878fc97 Merge pull request #3871 from sbwalker/dev
include render mode html comment
2024-02-22 08:00:24 -05:00
68d9984d64 include render mode html comment 2024-02-22 08:00:08 -05:00
c4d293143d Updates Bootstrap to version 5.3.2 2024-02-21 21:23:27 -08:00
b08d91a218 handle focus error on blazor web assembly when verifying email address 2024-02-22 00:33:45 +01:00
1c586d8811 Merge branch 'dev' into 3805-stop-registration-redirect-without-verification 2024-02-22 00:22:21 +01:00
f5e13c25a7 Merge pull request #3822 from pyramidsbuilder/fix-account-lockout-4
fix account lockout to read from correct setting, consider timezone o…
2024-02-21 16:34:54 -05:00
6e267b8825 Merge pull request #3867 from thabaum/site-settings-savesite-reload
Fixes #3863 - Site Settings: Always reload the page on SaveSite()
2024-02-21 15:55:07 -05:00
6cdfe70ac9 Merge pull request #3829 from thabaum/pages-edit-saving-reload
Admin\Pages\Edit.razor: Adds reload "true" boolean to the SavePage, NavigateTo() method - Fixes #3828
2024-02-21 15:49:54 -05:00
e8a0c693c9 Always reload the page on PageSave() 2024-02-21 12:04:04 -08:00
ac7db87592 Merge pull request #3778 from thabaum/update-theme-bootstrap
Updates theme bootstrap and bootswatch to version 5.3.2 - closes #3772
2024-02-21 13:55:33 -05:00
3d37a9eb8b Merge pull request #3866 from sbwalker/dev
update module and theme default templates to use ModuleBase methods rather than ModuleInstance methods
2024-02-21 13:42:32 -05:00
8c5613b182 update module and theme default templates to use ModuleBase methods rather than ModuleInstance methods 2024-02-21 13:42:15 -05:00
9e068335b6 Merge pull request #3862 from sbwalker/dev
update default site template with latest Blazor messaging
2024-02-21 10:50:25 -05:00
19ed98f265 update default site template with latest Blazor messaging 2024-02-21 10:50:10 -05:00
2aff36a1c0 Merge pull request #3861 from sbwalker/dev
fix #3827 - Cancel button should redirect to RedirectUrl (using PageState.ReturnUrl)
2024-02-21 10:20:14 -05:00
eac7fccbb4 fix #3827 - Cancel button should redirect to RedirectUrl (using PageState.ReturnUrl) 2024-02-21 10:19:55 -05:00
7562eaeb5f Merge pull request #3860 from sbwalker/dev
remove Delete option from Scheduled Jobs - they are automatically created at startup
2024-02-21 09:39:27 -05:00
7b38683985 remove Delete option from Scheduled Jobs - they are automatically created at startup 2024-02-21 09:39:06 -05:00
27763afbbe Merge pull request #3765 from thabaum/bootstrap-md-responsive-breakpoint
Sets responsive breakpoint match 767.98px = Bootstrap md - Fixes #3762
2024-02-21 09:33:21 -05:00
7a2b6f63c9 Merge pull request #3859 from sbwalker/dev
modified resx
2024-02-21 09:32:45 -05:00
2ad8413c6d modified resx 2024-02-21 09:32:31 -05:00
956c9000b8 Merge pull request #3823 from pyramidsbuilder/links-login-register-pages
added links from login to register and vice versa
2024-02-21 09:30:38 -05:00
838c2994a9 Merge pull request #3810 from zyhfish/task/fix-bug-3807
Fix #3807: parsing the data attributes.
2024-02-21 09:29:42 -05:00
9974095659 Merge pull request #3834 from zyhfish/task/token-replace-service
Fix #3833: introduce token replace class.
2024-02-21 09:29:29 -05:00
85e289fd4e Merge pull request #3858 from sbwalker/dev
add variability for StreamRendering based on render mode
2024-02-21 08:04:41 -05:00
fa17e7019a add variability for StreamRendering based on render mode 2024-02-21 08:04:24 -05:00
edcb24068a Merge pull request #3857 from sbwalker/dev
fix ModuleMessage - form name must be a constant value in static rendering or else it will not post correctly
2024-02-21 07:29:59 -05:00
38ead4909e fix ModuleMessage - form name must be a constant value in static rendering or else it will not post correctly 2024-02-21 07:29:39 -05:00
06b2eb7662 Merge pull request #3856 from sbwalker/dev
fix #3838 - Schedule Jobs looping after new install
2024-02-20 15:26:28 -05:00
5685f2699b fix #3838 - Schedule Jobs looping after new install 2024-02-20 15:26:15 -05:00
c6916fd71e Merge pull request #3855 from sbwalker/dev
fix #3839 - changing theme in Page Add/Edit throwing exception
2024-02-20 14:54:58 -05:00
df64abaf9c fix #3839 - changing theme in Page Add/Edit throwing exception 2024-02-20 14:54:48 -05:00
6ed717556a Merge pull request #3854 from sbwalker/dev
fix ModuleMessage so that it is not dependent on ModuleState
2024-02-20 14:31:33 -05:00
e8c64074f3 fix ModuleMessage so that it is not dependent on ModuleState 2024-02-20 14:31:22 -05:00
4af13058f0 Merge pull request #3853 from sbwalker/dev
fix route constructor
2024-02-20 14:15:49 -05:00
f3f223fa22 fix route constructor 2024-02-20 14:15:38 -05:00
e244b4b263 Merge pull request #3852 from sbwalker/dev
handle site level scripts in App component
2024-02-20 13:50:25 -05:00
ab09810bef handle site level scripts in App component 2024-02-20 13:50:09 -05:00
fbcde465ad Merge pull request #3850 from sbwalker/dev
move stylesheet injection to App component to eliminate flash on static rendering
2024-02-20 10:16:44 -05:00
0f0d168976 move stylesheet injection to App component to eliminate FOUC on static rendering 2024-02-20 10:16:19 -05:00
33d15ca66d Merge pull request #3848 from sbwalker/dev
Pass RenderMode and Runtime to Head component
2024-02-19 18:30:12 -05:00
4fad97e8b1 Pass RenderMode and Runtime to Head component 2024-02-19 18:30:01 -05:00
81071771d9 Merge pull request #3847 from sbwalker/dev
in static render mode do not filter scripts from head content
2024-02-19 16:46:07 -05:00
4db3bafeda in static render mode do not filter scripts from head content 2024-02-19 16:45:54 -05:00
29aff298b8 Merge pull request #3846 from sbwalker/dev
further refactoring of ManageStyleSheets
2024-02-19 16:24:54 -05:00
4271289db0 further refactoring of ManageStyleSheets 2024-02-19 16:24:43 -05:00
9818e7c101 Merge pull request #3845 from sbwalker/dev
refactor App to eliminate 2 database calls
2024-02-19 16:16:23 -05:00
121a865bb8 refactor App to eliminate 2 database calls 2024-02-19 16:16:08 -05:00
7af340de85 Merge pull request #3844 from sbwalker/dev
remove commented code
2024-02-19 15:47:35 -05:00
cdc0dee6f5 remove commented code 2024-02-19 15:47:23 -05:00
4cbefff8b4 Merge pull request #3843 from sbwalker/dev
inject CSS and JS on static rendering
2024-02-19 15:26:00 -05:00
acc562bd7f inject CSS and JS on static rendering 2024-02-19 15:25:48 -05:00
44b87dca2a Merge pull request #3842 from sbwalker/dev
add [StreamRendering] to Head component for static rendering
2024-02-19 14:30:29 -05:00
be98f786b3 add [StreamRendering] to Head component for static rendering 2024-02-19 14:30:09 -05:00
6f215cbff9 Merge pull request #3826 from thabaum/profile-registration-button-return-url-fix
Fix handling of returnurl parameter in UserProfile component - Fixes #3825
2024-02-18 10:46:53 -05:00
96a29e91e8 Merge pull request #3824 from thabaum/fixes-login-button-url
Ensure "login" route is included in login URL construction. Fixes #3766
2024-02-18 10:45:55 -05:00
e01a1a456c Merge pull request #3831 from thabaum/IPageService-spelling-correction
Corrects documentation spelling error for the word "Returns" in IPageService.cs
2024-02-18 10:44:42 -05:00
2561a6e00e Merge pull request #3832 from thabaum/Cleanup-ModuleDefinititionService-Namespaces
Cleanup module definitition service namespaces
2024-02-18 10:44:24 -05:00
e0bee0e0db Merge pull request #3837 from sbwalker/dev
document the mandatory StreamRendering attribute
2024-02-18 10:31:47 -05:00
7910d006ca document the mandatory StreamRendering attribute 2024-02-18 10:31:27 -05:00
778a651f7b Merge pull request #3836 from sbwalker/dev
ensure PageState and ModuleState are passed to ModuleMessage if an unhandled module exception occurs
2024-02-18 10:27:49 -05:00
2267dcb768 ensure PageState and ModuleState are passed to ModuleMessage in the event of an unhandled module exception 2024-02-18 10:27:12 -05:00
21e7c78744 Merge pull request #3835 from sbwalker/dev
update Npgsql.EntityFrameworkCore.PostgreSQL to version 8.0.2
2024-02-18 10:21:58 -05:00
54418957b6 update Npgsql.EntityFrameworkCore.PostgreSQL to version 8.0.2 2024-02-18 10:21:36 -05:00
Ben
77ce31128c Fix #3833: introduce token replace class. 2024-02-18 21:38:43 +08:00
79ce990644 cleanup unused namespaces 2024-02-17 18:22:01 -08:00
2262d44638 Removes unnecessary Oqtane.UI namespace 2024-02-17 18:17:13 -08:00
972601caf6 correct documentation spelling error 2024-02-17 17:55:38 -08:00
114ebac21b adds reload "true" boolean to the Save NavigateTo() method 2024-02-17 12:12:57 -08:00
57a86cd836 Fix handling of returnurl parameter in UserProfile component 2024-02-17 09:11:56 -08:00
a741b1b9ac Fix Login Button Control Url While On Login Page 2024-02-17 07:22:32 -08:00
5d64ea48ba added links from login to register and vice versa 2024-02-17 12:28:55 +01:00
db6c65c7e8 fix account lockout to read from correct setting, consider timezone offset and enable lockout 2024-02-16 23:17:56 +01:00
b68fc6187f localized usermanager email messages and message formatting to include site name and link #3794 2024-02-16 22:04:12 +01:00
766a190015 Merge pull request #3820 from sbwalker/dev
remove PageRepository reference in App
2024-02-16 15:36:36 -05:00
2c17551d50 remove PageRepository reference in App 2024-02-16 15:36:23 -05:00
739bc361bd Merge pull request #3819 from sbwalker/dev
ensure script resources are loaded before rendering ThemeBuilder
2024-02-16 15:15:13 -05:00
100fc20928 ensure script resources are loaded before rendering ThemeBuilder 2024-02-16 15:15:02 -05:00
f42e79f5cf Merge pull request #3818 from sbwalker/dev
get title and headcontent working again on interactive render mode
2024-02-16 15:08:15 -05:00
04da989108 get title and headcontent working again on interactive render mode 2024-02-16 15:08:04 -05:00
11017dd8dc Merge pull request #3815 from sbwalker/dev
fix #3811 - add PreserveCompilationContext back to server project
2024-02-16 11:17:26 -05:00
8d0aa65ab2 fix #3811 - add PreserveCompilationContext back to server project 2024-02-16 11:17:14 -05:00
8ffb9e6f11 Merge pull request #3814 from sbwalker/dev
fix issues with installer
2024-02-16 11:13:47 -05:00
b0487798c2 fix issues with installer 2024-02-16 11:13:31 -05:00
Ben
740b89258d Fix #3807: parsing the data attributes. 2024-02-16 19:26:01 +08:00
9026921214 display verification message instead of redirecting new user before email verification 2024-02-16 11:54:15 +01:00
df2aac3946 Merge pull request #3809 from sbwalker/dev
bump version to 5.1.0
2024-02-15 21:27:05 -05:00
829e004ee5 bump version to 5.1.0 2024-02-15 21:26:44 -05:00
072384eede Merge pull request #3808 from sbwalker/dev
load PageState in App component and pass to SiteRouter to optimize data loading
2024-02-15 21:17:49 -05:00
dcc8043cf6 load PageState in App component and pass to SiteRouter to optimize data loading 2024-02-15 21:17:23 -05:00
62c9484208 Merge pull request #3804 from sbwalker/dev
remove unnecessary using
2024-02-15 16:05:39 -05:00
ebadccbe25 remove unnecessary using 2024-02-15 16:05:27 -05:00
8013716158 Merge pull request #3803 from sbwalker/dev
create server-side SiteService
2024-02-15 15:48:33 -05:00
ed7904b673 create server-side SiteService 2024-02-15 15:48:18 -05:00
b2e3d33c80 Merge pull request #3797 from sbwalker/dev
fix #3793 - render issues on .NET MAUI
2024-02-15 10:22:37 -05:00
7d1b4d916e fix #3793 - render issues on .NET MAUI 2024-02-15 10:22:14 -05:00
0fb45d4584 Merge pull request #3791 from thabaum/update-project-dependencies-802
Update project to reference latest package dependency versions released with 8.0.2 - Closes #3790
2024-02-15 07:30:34 -05:00
0008919631 Merge pull request #3792 from thabaum/maui-connectivity-issue
Oqtane.Maui - Updates To New Namespace For DynamicComponent Type Oqtane.UI.Head - Fixes #3753
2024-02-15 07:29:42 -05:00
6bf8d19775 Merge pull request #3796 from thabaum/maui-app-css-app-form-button
adds app-form-button styles to sync with Oqtane.Server App.css - Fixes #3795
2024-02-15 07:29:21 -05:00
2e3ef87c42 adds app-form-button styles to sync with Oqtane.Server App.css 2024-02-14 14:55:21 -08:00
abdd5cf19b Updates To New Namespace For DynamicComponent Type - Fixes #3753 2024-02-14 13:30:41 -08:00
8a636736b4 Update project dependecies to 8.0.2 2024-02-14 12:53:14 -08:00
8fe2529306 Update project dependecies to 8.0.2 2024-02-14 12:52:26 -08:00
6db217387f Update project dependecies to 8.0.2 2024-02-14 12:51:10 -08:00
d33172df11 Update to latest project dependencies 2024-02-14 12:05:35 -08:00
206a83c935 Update to latest package dependencies 2024-02-14 11:59:02 -08:00
6a0935960b Update to latest package dependencies 2024-02-14 11:58:21 -08:00
3665a792d8 Update to latest package dependencies 2024-02-14 11:57:26 -08:00
90a58a1f37 Update to latest package dependencies 2024-02-14 11:55:51 -08:00
f81eaf62ff Update to latest package dependecies 2024-02-14 11:54:20 -08:00
8567f9b19f Updates package dependences to latest versions. 2024-02-14 11:52:25 -08:00
e33fc1a89b Merge pull request #3788 from sbwalker/dev
force ModuleActions to interactive render mode
2024-02-14 13:49:10 -05:00
872ec90654 force ModuleActions to interactive render mode 2024-02-14 13:48:56 -05:00
921f5524e7 Merge pull request #3787 from sbwalker/dev
fix #3781 - ModuleBase breaking change
2024-02-14 11:54:17 -05:00
a65959de3f fix #3781 - ModuleBase breaking change 2024-02-14 11:54:04 -05:00
bc095d087c Merge pull request #3786 from sbwalker/dev
force control panel to interactive render mode
2024-02-14 11:06:12 -05:00
3db744269e force control panel to interactive render mode 2024-02-14 11:05:49 -05:00
701e2f819b Merge pull request #3785 from sbwalker/dev
more Control Panel use cases supported on static rendering
2024-02-13 21:26:13 -05:00
88bf569752 more Control Panel use cases supported on static rendering 2024-02-13 21:25:53 -05:00
7283f48b36 Merge pull request #3784 from sbwalker/dev
changes to allow adding modules via control panel in static rendering  (note that onchange events have not been changed to an alternative approach yet)
2024-02-13 13:09:25 -05:00
f677b63c5c changes to allow adding modules via control panel in static rendering (note that onchange events have not been changed to an alternative approach yet) 2024-02-13 13:08:46 -05:00
b2e4172c12 Merge pull request #3783 from sbwalker/dev
enable close of modal admin container on static rendering
2024-02-13 11:58:15 -05:00
e0bec82a1c enable close of modal admin container on static rendering 2024-02-13 11:58:00 -05:00
6cf117b3d0 Merge pull request #3782 from sbwalker/dev
enable Edit Mode in static rendering
2024-02-12 16:00:16 -05:00
6bcf47fc4b enable Edit Mode in static rendering 2024-02-12 16:00:01 -05:00
6d968bbbd8 Merge pull request #3780 from sbwalker/dev
remove unused Action form field
2024-02-12 15:45:48 -05:00
8b803faf72 remove unused Action form field 2024-02-12 15:45:35 -05:00
d9bcb16d9e Merge pull request #3779 from sbwalker/dev
enable Admin Dashboard in static rendering
2024-02-12 15:43:36 -05:00
ead9f0b3c6 enable Admin Dashboard in static rendering 2024-02-12 15:43:24 -05:00
6168621a36 Update ThemeInfo.cs 2024-02-12 11:58:08 -08:00
d48c257b19 Update Bootstrap 5.3.2 Integrity 2024-02-12 11:53:42 -08:00
d723bbe3b7 Updates to bootstrap 5.3.2 2024-02-12 11:44:27 -08:00
f68e9c7681 updates bootstrap to latest 2024-02-12 11:41:33 -08:00
f7a59edf19 Merge pull request #3773 from sbwalker/dev
include script resources during static rendering
2024-02-12 12:40:26 -05:00
a4741e28c5 include script resources during static rendering 2024-02-12 12:40:11 -05:00
c48ca99817 Merge pull request #3770 from sbwalker/dev
allow prerender selection in all scenarios
2024-02-12 09:14:23 -05:00
2b6965f801 allow prerender selection in all scenarios 2024-02-12 09:14:05 -05:00
caec4f80bb Merge pull request #3769 from sbwalker/dev
remove debugging info from UI
2024-02-12 09:06:06 -05:00
9aa7672b17 remove debugging info from UI 2024-02-12 09:05:47 -05:00
8e03cf9fc8 Merge pull request #3768 from sbwalker/dev
Resolve issue where components are not being rendered interactively
2024-02-12 08:52:07 -05:00
8d9a050ad6 Resolve issue where components are not being rendered interactively 2024-02-12 08:51:41 -05:00
266e08817e sets responsive breakpoint to bootstrap md 767.98px 2024-02-10 09:43:18 -08:00
6c3526d47e sets responsive breakpoint to 767.98 bootstrap md 2024-02-10 09:42:40 -08:00
19adfd5116 sets responsive breakpoint to bootstrap md 767.98px 2024-02-10 09:40:46 -08:00
485f7fdcef Merge pull request #3764 from sbwalker/dev
updates to make identical to POC - still not working
2024-02-10 11:46:32 -05:00
856afcf3bf updates to make identical to POC - still not working 2024-02-10 11:46:07 -05:00
934b5e344f Merge pull request #3759 from thabaum/update-maui-packages
Fixes #3758 Updates Referenced Maui Packages To Latest
2024-02-10 11:27:34 -05:00
82eb8f14aa Merge pull request #3763 from sbwalker/dev
fix #3760 include form button wrapper CSS class for inline-block
2024-02-10 11:26:14 -05:00
caa9cc213d fix #3760 include form button wrapper CSS class for inline-block 2024-02-10 11:25:54 -05:00
403325d9dd Updates Maui Project Package References
includes     <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.6" /> which will otherwise be requested as an update from 8.0.3 in package manager.
2024-02-09 15:18:09 -08:00
62b3ca2fb9 Updates Referenced Maui Packages To Latest 2024-02-09 14:19:25 -08:00
e6034223f8 Merge pull request #3757 from sbwalker/dev
change RESX values for Runtime
2024-02-09 16:35:43 -05:00
da02bea945 change RESX values for Runtime 2024-02-09 16:35:27 -05:00
dd308d9276 Merge pull request #3756 from sbwalker/dev
Interactivity needs to be selectable regardless of the default render mode
2024-02-09 16:24:49 -05:00
fce72cad55 Interactivity needs to be selectable regardless of the default render mode 2024-02-09 16:24:30 -05:00
901b23e5ae Merge pull request #3755 from sbwalker/dev
create component using RenderTreeBuilder
2024-02-09 15:46:59 -05:00
df4d4d36bc create component using RenderTreeBuilder 2024-02-09 15:46:44 -05:00
408c56bfcf Merge pull request #3752 from sbwalker/dev
rename RenderMode class and adding usings
2024-02-09 14:34:48 -05:00
ea75ddfa85 rename RenderMode class and adding usings 2024-02-09 14:34:33 -05:00
bda5619b97 Merge pull request #3751 from sbwalker/dev
specify default interactive render mode
2024-02-09 11:00:08 -05:00
f6fb3cc766 specify default interactive render mode 2024-02-09 10:59:51 -05:00
7c3cb118a4 Merge pull request #3750 from sbwalker/dev
improve debug message
2024-02-09 09:10:23 -05:00
d03565ad95 improve debug message 2024-02-09 09:10:03 -05:00
c0f5746d1d Merge pull request #3749 from sbwalker/dev
add text to display render mode
2024-02-09 08:56:41 -05:00
a686bec025 add text to display render mode 2024-02-09 08:56:25 -05:00
c0d36bb85e Merge pull request #3748 from sbwalker/dev
preserve backward compatibility but flag methods as obsolete
2024-02-09 08:47:41 -05:00
e6df8dcd2e preserve backward compatibility but flag methods as obsolete 2024-02-09 08:47:20 -05:00
6f3fd99130 Merge pull request #3746 from sbwalker/dev
render mode optimization
2024-02-08 15:58:44 -05:00
b5f7106780 render mode optimization 2024-02-08 15:58:31 -05:00
e2f6dcab01 Merge pull request #3745 from sbwalker/dev
set Html/Text module to Static rendering
2024-02-08 15:53:47 -05:00
ff2f218bf0 set Html/Text module to Static rendering 2024-02-08 15:53:24 -05:00
902ed6e287 Merge pull request #3744 from sbwalker/dev
implement RenderModeBoundary
2024-02-08 15:47:51 -05:00
a40b49f2ed implement RenderModeBoundary 2024-02-08 15:47:25 -05:00
fc3b55b135 Merge pull request #3743 from sbwalker/dev
add @attribute [StreamRendering] attribute to Routes.razor and rollback #3739
2024-02-08 09:26:06 -05:00
07bd5c633e add @attribute [StreamRendering] attribute to Routes.razor and remove #3739 2024-02-08 09:25:31 -05:00
f70dc14340 Merge pull request #3741 from sbwalker/dev
remove UseBlazorFrameworkFiles as no longer needed
2024-02-06 12:43:25 -05:00
3d49ab2ae0 remove UseBlazorFrameworkFiles as no longer needed 2024-02-06 12:42:31 -05:00
a133c39167 Merge pull request #3740 from sbwalker/dev
update project files to make consistent with Blazor template
2024-02-06 11:41:04 -05:00
c9c8e20511 update project files to make consistent with Blazor template 2024-02-06 11:40:44 -05:00
509ff7e833 Merge pull request #3739 from sbwalker/dev
temporary hack to allow Static rendering to (sort of) work - this will need to be removed later
2024-02-06 11:28:59 -05:00
a7a5fdb7f5 temporary hack to allow Static rendering to (sort of) work - this will need to be removed later 2024-02-06 11:28:37 -05:00
cf9ef281ce Merge pull request #3738 from sbwalker/dev
optrimization to eliminate file lookup in Logo control
2024-02-06 11:26:47 -05:00
6345335be2 optrimization to eliminate file lookup in Logo control 2024-02-06 11:26:31 -05:00
a008ec3729 Merge pull request #3732 from sbwalker/dev
use Runtimes constant
2024-02-02 14:38:49 -05:00
e7a48f3909 use Runtimes constant 2024-02-02 14:38:37 -05:00
718553373f Merge pull request #3731 from sbwalker/dev
changes for static rendering
2024-02-02 13:08:18 -05:00
310772d7fe changes for static rendering 2024-02-02 13:08:05 -05:00
213e6fab57 Merge pull request #3730 from sbwalker/dev
update .NET MAUI client to reflect changes
2024-02-02 10:56:35 -05:00
b7dbed5cd4 update .NET MAUI client to reflect changes 2024-02-02 10:56:24 -05:00
b621f2c24d Merge pull request #3729 from sbwalker/dev
move root UI components to UI namespace
2024-02-02 10:38:29 -05:00
21b9b090f9 move root UI components to UI namespace 2024-02-02 10:38:16 -05:00
709121b07f Merge pull request #3728 from sbwalker/dev
Fix #3723 - cancel from login not redirecting properly
2024-02-02 09:07:03 -05:00
bb02a17e44 Fix #3723 - cancel from login not redirecting properly 2024-02-02 09:06:51 -05:00
fd40c58b9c Merge pull request #3724 from thabaum/login-cancel-null-exception
Fixes: #3723 - Fix refresh() unnecessary conditional check for page values
2024-02-02 09:06:08 -05:00
b7a6f1249d Merge pull request #3727 from sbwalker/dev
change extension method name to reflect actual purpose
2024-02-02 08:54:16 -05:00
71125f07cc change extension method name to reflect actual purpose 2024-02-02 08:54:01 -05:00
8500f5b437 Fix refresh() conditional check for page 2024-02-01 14:36:14 -08:00
eb25d9d7af Merge pull request #3722 from sbwalker/dev
add support for Razor Pages
2024-02-01 16:49:42 -05:00
033c85fc4b add support for Razor Pages 2024-02-01 16:49:29 -05:00
1663731489 Merge pull request #3721 from sbwalker/dev
use new Cascading Authentication State Services
2024-02-01 15:47:16 -05:00
1f65d47811 use new Cascading Authentication State Services 2024-02-01 15:47:03 -05:00
897cba3d07 Merge pull request #3720 from sbwalker/dev
remove unused NavigationManager reference
2024-02-01 15:19:29 -05:00
f0e2247f06 remove unused NavigationManager reference 2024-02-01 15:19:15 -05:00
1470ec60db Merge pull request #3719 from sbwalker/dev
remove unnecessary constants
2024-02-01 10:46:06 -05:00
7c04792777 remove unnecessary constants 2024-02-01 10:45:52 -05:00
6e750a2af0 Merge pull request #3718 from sbwalker/dev
fix Runtimes property behavior
2024-02-01 10:08:55 -05:00
7640dab380 fix Runtimes property behavior 2024-02-01 10:08:41 -05:00
6c10908cb7 Merge pull request #3717 from sbwalker/dev
add RenderMode to IModuleControl
2024-02-01 09:59:43 -05:00
abd235f332 add RenderMode to IModuleControl 2024-02-01 09:59:28 -05:00
4a638e82cc Merge pull request #3716 from sbwalker/dev
use new contants in .NET MAUI
2024-02-01 09:48:00 -05:00
156d39490e use new contants in .NET MAUI 2024-02-01 09:47:46 -05:00
a39968868f Update appsettings.release.json 2024-02-01 09:10:13 -05:00
e0587ad17b Update appsettings.json 2024-02-01 09:09:58 -05:00
06106f3831 Merge pull request #3715 from sbwalker/dev
split RenderMode and Runtime configuration
2024-02-01 09:08:57 -05:00
1e332ed075 split RenderMode and Runtime configuration 2024-02-01 09:08:39 -05:00
cef56cb5f1 Merge pull request #3714 from sbwalker/dev
fix site Hybrid behavior
2024-01-31 16:40:09 -05:00
97762712e6 fix site Hybrid behavior 2024-01-31 16:39:46 -05:00
4575996995 Merge pull request #3713 from sbwalker/dev
use new RenderModes constant
2024-01-31 16:26:47 -05:00
9a4594227e use new RenderModes constant 2024-01-31 16:26:35 -05:00
399bec62c2 Merge pull request #3712 from sbwalker/dev
remove app.UseAntiForgery as it is handled by the IAntiforgery service
2024-01-31 16:21:37 -05:00
177d015fc6 remove app.UseAntiForgery as it is handled by the IAntiforgery service 2024-01-31 16:21:23 -05:00
afd62ceeeb Merge pull request #3711 from sbwalker/dev
document CORS policy
2024-01-31 16:16:08 -05:00
44c088c96d document CORS policy 2024-01-31 16:15:57 -05:00
cf65347cd8 Merge pull request #3710 from sbwalker/dev
remove commented code and add SignalR options
2024-01-31 16:13:04 -05:00
9fe54c5d21 remove commented code and add SignalR options 2024-01-31 16:12:53 -05:00
0210ef2764 Merge pull request #3709 from sbwalker/dev
fix .NET MAUI integration
2024-01-31 15:43:28 -05:00
c66982c9bc fix .NET MAUI integration 2024-01-31 15:43:17 -05:00
a88be30c3f Update appsettings.release.json 2024-01-31 15:31:12 -05:00
155cd31ced Update appsettings.json 2024-01-31 15:30:48 -05:00
52dc77a00f Merge pull request #3708 from sbwalker/dev
remove Runtime from System Info
2024-01-31 15:30:18 -05:00
c5de56790a remove Runtime from System Info 2024-01-31 15:30:07 -05:00
d97cb4c360 Merge pull request #3707 from sbwalker/dev
render mode integration
2024-01-31 15:22:39 -05:00
8e499d164a render mode integration 2024-01-31 15:22:21 -05:00
764e1ac35f Merge pull request #3706 from sbwalker/dev
add support for Jwt Token creation
2024-01-31 11:11:51 -05:00
69e4fcfc76 add support for Jwt Token creation 2024-01-31 11:11:40 -05:00
951071e7ba Merge pull request #3705 from sbwalker/dev
remove unnecessary database call to GetSettings()
2024-01-31 10:58:40 -05:00
5e82700871 remove unnecessary database call to GetSettings() 2024-01-31 10:58:28 -05:00
4c706a213a Merge pull request #3704 from sbwalker/dev
add support for visitor tracking
2024-01-31 10:49:38 -05:00
d0da1f43a9 add support for visitor tracking 2024-01-31 10:49:26 -05:00
4afc439169 Merge pull request #3703 from sbwalker/dev
add support for page not found functionality
2024-01-31 10:03:40 -05:00
e47690dd52 add support for page not found functionality 2024-01-31 10:03:25 -05:00
7859aa0ce8 Merge pull request #3699 from thabaum/patch-7
Removed unintended space added from PR #3692.
2024-01-31 09:41:28 -05:00
710c192e39 Merge pull request #3702 from sbwalker/dev
add support for Render Modes and Prerendering
2024-01-31 09:41:00 -05:00
50e179f7a8 add support for Render Modes and Prerendering 2024-01-31 09:40:47 -05:00
980a9d0640 Merge pull request #3701 from sbwalker/dev
implement non-default alias redirect
2024-01-31 08:19:16 -05:00
fdfbf54808 implement non-default alias redirect 2024-01-31 08:18:56 -05:00
fe8b0d99e5 Merge pull request #3700 from sbwalker/dev
resolve antiforgery issue
2024-01-31 07:34:06 -05:00
7e817a5808 resolve antiforgery issue 2024-01-31 07:33:52 -05:00
23b68bd9f9 Removed unnecessary space. 2024-01-30 15:48:40 -08:00
0a8bbc7d3a Merge pull request #3692 from leigh-pointer/MenuWhiteSpace
Menu theme fix #3680
2024-01-30 16:39:00 -05:00
0f5200aaf8 Merge pull request #3697 from sbwalker/dev
initial changes to migrate to new Blazor approach in .NET 8
2024-01-30 16:04:04 -05:00
82d7b9cf05 initial changes to migrate to new Blazor approach in .NET 8 2024-01-30 16:03:50 -05:00
0f5fafac8d Merge pull request #3696 from sbwalker/dev
add IDisposable declaration to accompany existing Dispose() method
2024-01-30 13:14:01 -05:00
7fcfffba6f add IDisposable declaration to accompany existing Dispose() method 2024-01-30 13:13:49 -05:00
13e9ef4c34 Merge pull request #3693 from sbwalker/dev
bump version to 5.0.3
2024-01-29 12:55:53 -05:00
ea04c7d5eb bump version to 5.0.3 2024-01-29 12:55:39 -05:00
8bf29528e3 Updated Theme Template
Template updated with white-space: nowrap; and corrected the app-menu class
2024-01-29 07:19:30 +01:00
c6f65debcf Menu theme fix #3680
Added white-space: nowrap; to the .app-menu .nav-item
2024-01-28 11:56:55 +01:00
370b39a139 Merge branch 'release/v5.0.1' into dev 2024-01-27 21:18:58 -08:00
7b7e64576f Update appsettings.json 2024-01-27 20:30:20 -08:00
d8b717a879 Update README.md 2024-01-25 15:08:56 -05:00
3967017ebb Merge pull request #3687 from oqtane/master
5.0.2 release
2024-01-25 14:56:55 -05:00
d93862043a Merge pull request #3686 from oqtane/dev
5.0.2 release
2024-01-25 14:56:33 -05:00
719276b32a Merge pull request #3685 from sbwalker/dev
fix incorrect migration id
2024-01-25 14:40:48 -05:00
bf13f06e68 fix incorrect migration id 2024-01-25 14:40:32 -05:00
9f770d08f5 Merge pull request #3684 from sbwalker/dev
update default Module and Theme template to .NET 8.0.1 to match framework
2024-01-25 13:50:32 -05:00
e62c529c1f update default Module and Theme template to .NET 8.0.1 to match framework 2024-01-25 13:50:13 -05:00
4e1fc9b031 Merge pull request #3681 from zyhfish/task/fix-bug-3648
fix #3648: update the template to correct the entity table name.
2024-01-25 13:41:13 -05:00
7d175ad38d Merge pull request #3683 from sbwalker/dev
resolve regression installation issue with PostgreSQL
2024-01-25 13:39:35 -05:00
de2c56560e resolve regression installation issue with PostgreSQL 2024-01-25 13:39:23 -05:00
0db413cb18 Merge pull request #3682 from sbwalker/dev
fix #3653 - mySQL installation failing on Rows reserved word
2024-01-25 10:59:32 -05:00
7c6424e05c fix #3653 - mySQL installation failing on Rows reserved word 2024-01-25 10:59:18 -05:00
Ben
3c328a00b5 fix #3648: update the template to correct the entity table name. 2024-01-25 23:00:45 +08:00
e36f13c595 Merge pull request #3679 from sbwalker/dev
upgrade to MySQL dependencies
2024-01-24 16:49:23 -05:00
38a5cc33e8 upgrade to MySQL dependencies 2024-01-24 16:49:02 -05:00
245a3a73d8 Merge pull request #3677 from sbwalker/dev
improvements to .NET MAUI file upload based on #3674 (credit @thabaum)
2024-01-24 09:37:45 -05:00
d57d7ec4d8 improvements to .NET MAUI file upload based on #3674 (credit @thabaum) 2024-01-24 09:37:27 -05:00
09a4e4a6a5 Merge pull request #3673 from sbwalker/dev
remove unnecessary service and usings
2024-01-23 13:14:40 -05:00
d9beb4b660 remove unnecessary service and usings 2024-01-23 13:14:28 -05:00
63507a5567 Update README.md 2024-01-23 11:07:37 -05:00
e42dc259d8 Merge pull request #3672 from sbwalker/dev
prepare for 5.0.2 release
2024-01-23 11:06:30 -05:00
f59f8d1937 prepare for 5.0.2 release 2024-01-23 11:06:15 -05:00
0387bde81b Merge pull request #3671 from sbwalker/dev
fix #3669 add CORS policy and use Jwt with XHR to allow file uploads to work in .NET MAUI
2024-01-23 10:34:39 -05:00
b8fe95b945 fix #3669 add CORS policy and use Jwt with XHR to allow file uploads to work in .NET MAUI 2024-01-23 10:34:18 -05:00
792a1652e3 Merge pull request #3668 from sbwalker/dev
fix typo
2024-01-22 08:38:46 -05:00
4816bfa26d fix typo 2024-01-22 08:38:31 -05:00
95d1680ac3 Merge pull request #3667 from sbwalker/dev
fix #3656 - UploadableFiles and ImageFiles settings not loaded properly to handle empty string value resulting in upload issues
2024-01-22 08:24:20 -05:00
5e1e6aea16 fix #3656 - UploadableFiles and ImageFiles settings not loaded properly to handle empty string value resulting in upload issues 2024-01-22 08:24:01 -05:00
00696943d1 Merge pull request #3660 from sbwalker/dev
update license
2024-01-19 16:44:17 -05:00
c1d293f9f9 update license 2024-01-19 16:44:06 -05:00
d4d61d10bc Merge pull request #3659 from sbwalker/dev
improve help text for autocomplete
2024-01-19 15:36:01 -05:00
c09e5e6552 improve help text for autocomplete 2024-01-19 15:35:48 -05:00
ab08732ba8 Merge pull request #3652 from thabaum/ENH-Adds-Profile-Autocomplete-Setting
Enh: Autocomplete Attribute Enhancement
2024-01-19 15:25:13 -05:00
584a7eb9e2 Merge pull request #3598 from thabaum/module-creator-notification-tool-tips
Module Creator Owner/Name + Notification Help Text Includes Warning Not To Use The Word "Oqtane".  Fixes #3597
2024-01-19 15:18:42 -05:00
d44b04f425 Merge pull request #3658 from sbwalker/dev
update copyright year
2024-01-19 14:54:05 -05:00
eeec04b21a update copyright year 2024-01-19 14:53:54 -05:00
0642bc28bc Merge pull request #3657 from sbwalker/dev
do not include Licensing assembly with framework but prevent uninstall
2024-01-19 13:22:52 -05:00
2b12b67582 do not include Licensing assembly with framework but prevent uninstall 2024-01-19 13:22:38 -05:00
d9b575b051 undo changes to autocomplete. 2024-01-19 08:15:48 -08:00
c6dbb41724 removes recently added autocomplete attributes 2024-01-18 14:41:02 -08:00
ea4c1bf5e5 removes hardcoded autocomplete attributes last added 2024-01-18 14:38:31 -08:00
67afc050b8 Adds to form autocomplete="on" attribute and setting. 2024-01-18 14:23:10 -08:00
6e90da90f1 adds autocomplete to email and username + fixes a typo 2024-01-18 14:08:05 -08:00
26872c829b adds autocomplete attribute to username, email and display name input elements. 2024-01-18 14:06:10 -08:00
34f32c8ba5 Merge pull request #3649 from thabaum/clean-protocal-save-alias
Cleans protocol to check for duplicate alias prior to saving.  Fixes #3647
2024-01-18 07:57:53 -05:00
b0d847dc18 Merge pull request #3654 from thabaum/XMLHttpRequest-statusText
Updates request.status to request.statusText in Interop.js
2024-01-18 07:57:31 -05:00
adabef9706 Merge pull request #3655 from sbwalker/dev
fix issue when inserting images into RichTextEditor
2024-01-17 13:36:05 -05:00
474adf2d53 fix issue when inserting images into RichTextEditor 2024-01-17 13:35:52 -05:00
4f23ad37f5 Sets Profile Autocomplete Property 50 Character Limit 2024-01-17 09:07:03 -08:00
eb6b160377 updates autocomplete default tooltip and limits characters to 30. 2024-01-16 17:56:32 -08:00
0770e00d8d Updates Autocomplete.HelpText 2024-01-16 17:46:30 -08:00
ab0e95177e Updates request.status to request.statusText 2024-01-16 17:30:41 -08:00
cfd9e4b256 Updates request.status to request.statusText 2024-01-16 17:29:54 -08:00
bfed0ed791 Refactor SaveAlias method and add URL protocol check
Restructured the SaveAlias method for improved readability and added a check to handle cases where the _aliasname contains a URL protocol (e.g., "://"). This ensures proper handling of different URL formats.
2024-01-16 10:43:24 -08:00
3cec9f7ee0 fix formatting 2024-01-15 09:59:22 -08:00
3a5dc62908 Sanitize _aliasname by removing protocols 2024-01-15 09:56:11 -08:00
e0cdfcf403 adds Autocomplete property 2024-01-15 09:30:37 -08:00
439866216c adds autocomplete attribute to select element 2024-01-15 09:10:12 -08:00
a1b0731665 profile autocomplete migration 2024-01-15 08:24:06 -08:00
bcc216fd2e Merge pull request #3645 from thabaum/file-controller-upload-null
Handle null or empty formfile in UploadFile Method - Fixes #3646
2024-01-15 08:55:04 -05:00
574d848828 Merge pull request #3644 from thabaum/interop-xrs-status-update
Interop.js xrs status update Fixes #3643
2024-01-15 08:54:24 -05:00
22acc2307c remove extra line 2024-01-13 21:09:41 -08:00
d01a3c327e remove space 2024-01-13 21:09:00 -08:00
7c52b6ab23 remove name from password input 2024-01-13 21:07:08 -08:00
23d27aee6b ENH: Adds Profile Properties Autocomplete 2024-01-13 21:04:15 -08:00
9315358fa6 adds autocomplete 2024-01-13 20:59:42 -08:00
83aaa94cfe ENH: Profile Properties Autocomplete Setting 2024-01-13 20:54:31 -08:00
7744099ee5 cleans protocol to check for duplicate alias prior to saving 2024-01-13 13:09:17 -08:00
35bb6b62d8 Handle null or empty formfile in UploadFile Method 2024-01-12 14:08:15 -08:00
99844931f4 XRS status error update Fixes #3643 2024-01-12 13:43:02 -08:00
d8c34a7cdf XRS status error update Fixes #3643
Resolved an issue with XRS status not updating correctly. This commit addresses the problem and ensures the status is now accurately reflected.

Fixes #3643
2024-01-12 13:38:15 -08:00
c284edcd81 Merge pull request #3630 from thabaum/upgrade-nuget-packages
Upgrade NuGet Packages for Oqtane Framework
2024-01-12 16:37:42 -05:00
f5d4b352b3 Merge pull request #3632 from leigh-pointer/SchedStartEndDateCheck
Start end End date Range check on Job Items
2024-01-12 16:28:22 -05:00
e44b31d755 Merge pull request #3641 from sbwalker/dev
fix issue where rich text was not being refreshed in the editor when content changed, and original rich text was not always preserved
2024-01-12 15:49:53 -05:00
3a28068b48 fix issue where rich text was not being refreshed in the editor when content changed, and original rich text was not always preserved 2024-01-12 15:49:34 -05:00
03433b00d2 Merge pull request #3639 from sbwalker/dev
fix #3637 - ensure ServerState Scripts only contains site level script resources
2024-01-12 08:20:17 -05:00
6f39ebf48f fix #3637 - ensure ServerState Scripts only contains site level script resources 2024-01-12 08:19:58 -05:00
949ca00dbb Merge pull request #3638 from sbwalker/dev
add defensive null check
2024-01-12 08:15:44 -05:00
bfdf1ee8f5 add defensive null check 2024-01-12 08:15:30 -05:00
e047d4e8a6 Start end End date Range check
Checks that the Start date starts before the End date.
Message added to Resx
2024-01-10 14:49:47 +01:00
15cf2069b6 Update NuGet Packages to New Versions
This commit updates the versions of several NuGet packages used in the project. The following packages have been upgraded:

- Microsoft.EntityFrameworkCore from 8.0.0 to 8.0.1
- Microsoft.EntityFrameworkCore.Relational from 8.0.0 to 8.0.1
- System.Text.Json from 8.0.0 to 8.0.1

The versions of Microsoft.Extensions.DependencyInjection.Abstractions and System.ComponentModel.Annotations remain unchanged.
2024-01-09 14:09:56 -08:00
564b0ee0c4 Upgrade NuGet Packages to Latest Versions
This commit updates the versions of several NuGet packages used in the project. The following packages have been upgraded:

- Microsoft.AspNetCore.Components.WebAssembly.Server from 8.0.0 to 8.0.1
- Microsoft.AspNetCore.Identity.EntityFrameworkCore from 8.0.0 to 8.0.1
- Microsoft.Data.SqlClient from 5.2.0-preview3.23201.1 to 5.2.0-preview4.23342.2
- Microsoft.EntityFrameworkCore from 8.0.0 to 8.0.1
- Microsoft.EntityFrameworkCore.Design from 8.0.0 to 8.0.1
- Microsoft.Extensions.Localization from 8.0.0 to 8.0.1
- Microsoft.AspNetCore.Authentication.OpenIdConnect from 8.0.0 to 8.0.1
- Microsoft.Data.Sqlite.Core from 8.0.0 to 8.0.1

The versions of SixLabors.ImageSharp, Swashbuckle.AspNetCore, SQLitePCLRaw.bundle_e_sqlite3, and Oqtane.Licensing remain unchanged.
2024-01-09 14:08:09 -08:00
b454932ff5 Upgrade multiple NuGet packages
Upgraded the following NuGet packages:
- Microsoft.EntityFrameworkCore.Sqlite from v8.0.0 to v8.0.1
2024-01-09 14:03:24 -08:00
191c07b6a1 Upgrade multiple NuGet packages
Upgraded the following NuGet packages:
- Microsoft.EntityFrameworkCore.SqlServer from v8.0.0 to v8.0.1
2024-01-09 13:58:28 -08:00
5b0deb9fc2 Upgrade multiple NuGet packages
Upgraded the following NuGet packages:
- EFCore.NamingConventions from v8.0.0-rc.2 to v8.0.2
- Microsoft.EntityFrameworkCore.Relational from v8.0.0 to v8.0.1
2024-01-09 13:55:56 -08:00
297ec64bde Upgrade multiple NuGet packages 2024-01-09 13:53:39 -08:00
a9b85caeb7 Upgrade multiple NuGet packages
Upgraded the following NuGet packages:
- Microsoft.AspNetCore.Components.Authorization from v8.0.0 to v8.0.1
- Microsoft.AspNetCore.Components.WebAssembly from v8.0.0 to v8.0.1
- Microsoft.Extensions.Localization from v8.0.0 to v8.0.1
2024-01-09 13:44:47 -08:00
e30b883148 Merge pull request #3628 from thabaum/update-getting-started-readme
Clarify Getting Started Instructions. Fixes #3627
2024-01-09 14:53:53 -05:00
cd6be0d755 Merge pull request #3624 from thabaum/documentation-spelling-correction
Documentation spelling correction.  Fixes #3623
2024-01-09 14:52:55 -05:00
95b74c5f2f Fix capitalization in list items. 2024-01-08 14:46:37 -08:00
45f26bb22e Clarify Getting Started Instructions. 2024-01-08 14:10:03 -08:00
09b0e09932 Documentation Spelling Correction 2024-01-07 11:10:53 -08:00
ea9d88009f Documentation Spelling Correction 2024-01-07 11:09:06 -08:00
e5013c918e Documentation Spelling Correction 2024-01-07 11:08:08 -08:00
4b45103a4e Documentation Spelling Correction 2024-01-07 11:07:35 -08:00
1ea28411da Documentation Spelling Correction 2024-01-07 11:07:08 -08:00
e27fce1227 Documentation Spelling Correction 2024-01-07 11:06:32 -08:00
cf3b8378bd Documentation Spelling Correction 2024-01-07 11:05:46 -08:00
9f07532140 documentation spelling correction 2024-01-07 10:59:11 -08:00
f1aedc619e Merge pull request #3622 from sbwalker/dev
fix #3584 - browse/edit using relative path for current site
2024-01-06 15:29:45 -05:00
5f778e706f fix #3584 - browse/edit using relative path for current site 2024-01-06 15:29:28 -05:00
ee15663679 Merge pull request #3620 from sbwalker/dev
improve ShouldRender logic
2024-01-06 08:52:26 -05:00
c271d4bfe4 improve ShouldRender logic 2024-01-06 08:52:05 -05:00
99188f7427 Merge pull request #3619 from sbwalker/dev
more rendering optimizations
2024-01-06 08:42:28 -05:00
88a07ecf63 more rendering optimizations 2024-01-06 08:42:07 -05:00
f1af2e35cd Merge pull request #3616 from sbwalker/dev
remove commented code
2024-01-05 12:14:57 -05:00
352e20f01b remove commented code 2024-01-05 12:14:43 -05:00
f7d10a6cf1 Merge pull request #3602 from leigh-pointer/ENH#3538-PgModDateActive
Start Date and Expiry Date for Module instances and Pages #3538
2024-01-05 12:09:19 -05:00
6a5808077c Merge pull request #3608 from thabaum/readme-add-marketplace-button
README - adds marketplace information for issue #3607
2024-01-05 12:08:20 -05:00
09be11b5a8 Merge pull request #3615 from sbwalker/dev
changed max profiel field rows to 10
2024-01-05 12:06:52 -05:00
5117c1a528 changed max profiel field rows to 10 2024-01-05 12:06:36 -05:00
ead9857203 Merge pull request #3610 from W6HBR/dev
Update Oqtane.Client\Modules\Admin\Profiles\Edit.razor to fix breaking changes
2024-01-05 12:04:30 -05:00
cd3493e040 Merge pull request #3614 from sbwalker/dev
improved rendering optimization
2024-01-05 11:53:57 -05:00
02c22c1894 improved rendering optimization 2024-01-05 11:49:57 -05:00
8b41a03080 Modified Logic from || to &&
UserSecurity.IsAuthorized && Utilities.IsPageModuleVisible fixed
2024-01-05 10:15:51 +01:00
306f4f119b Merge pull request #3613 from sbwalker/dev
Fix #3604 - display message if user is attempting to run the application prior to performing a full compilation
2024-01-04 16:40:36 -05:00
3dc28c7291 Fix #3604 - display message if user is attempting to run the application prior to performing a full compilation 2024-01-04 16:40:15 -05:00
f2f2215059 Merge pull request #3611 from sbwalker/dev
component rendering optimizations
2024-01-04 13:48:06 -05:00
f75179b2f6 component rendering optimizations 2024-01-04 13:47:51 -05:00
3ead35c984 Update (Profiles) Edit.razor to fix breaking changes
Prior functionality allowed 4 characters for "order" which now causes validation errors for any order value > 99.  This change allows a value of up to 9999 which is consistent with the prior 4 character length value.

Prior functionality allowed 2 characters for "rows" which now causes validattion error for any row count > 10.  This change allows a value up to 99 which is consistent with the prior 2 character length value.
2024-01-04 10:12:17 -08:00
efe20a1fe8 Adds Marketplace Section 2024-01-03 10:59:14 -08:00
ab1e56a14e Updates Marketplace Message 2024-01-03 10:49:14 -08:00
055d6bf601 Adjust Marketplace Placement 2024-01-03 10:48:24 -08:00
683c3e96d6 Update Marketplace Message 2024-01-03 10:47:13 -08:00
d8e414a4a2 Icon and Link for Oqtane Marketplace 2024-01-03 10:45:43 -08:00
9237d68b79 Update Marketplace Icon 2024-01-03 10:35:24 -08:00
12a14fbe29 Adds Marketplace Button 2024-01-03 10:25:13 -08:00
22e4e4efc1 Updates
Loops tighter
Updated Logout base
SiteController corrected.
2024-01-03 12:12:27 +01:00
588327fd68 Merge pull request #3605 from sbwalker/dev
synchronize static assets with .NET MAUI project
2024-01-02 15:25:21 -05:00
d35ef2d360 synchronize static assets with .NET MAUI project 2024-01-02 15:25:07 -05:00
5ce5193430 Modifications 2024-01-02 16:09:54 +01:00
6e74215b2e Merge pull request #3600 from thabaum/clear-module-message
Clear Module Message Prior To Adding A Message To UI. Fixes #3599
2024-01-02 08:21:06 -05:00
884a9835c4 Merge pull request #3586 from thabaum/patch-6
Refreshes Admin Settings Page When User Updates Logo.  Fixes #3582
2024-01-02 08:19:37 -05:00
233f40f3e9 Start Date and Expiry Date for Module instances and Pages #3538
This is complete excluding Reporting and Notifications which can be added at a later date.  I just really wanted to get the schema and the functionality into place.
2023-12-31 12:21:38 +01:00
9b24e61033 Clear Module Message Proir To Adding A Message To UI 2023-12-29 12:49:49 -08:00
286928d59e Merge tag 'v5.0.1' into dev 2023-12-29 11:54:39 -08:00
47cee5f6a1 Updates Module Owner/Name HelpText 2023-12-29 11:39:35 -08:00
6820b748f7 Updates Module Name/Owner and Notification Text 2023-12-29 11:37:31 -08:00
42422845b0 Updates Owner/Module Name Tooltip/Notification 2023-12-29 11:00:29 -08:00
8ed11cdc07 Adds the comment for client logo refresh boolean 2023-12-23 12:02:58 -08:00
006cd1ee89 Refresh Page On Client After Saving Changed Logo 2023-12-23 11:26:57 -08:00
49f7ee6042 change to reload from refresh to update site logo 2023-12-23 09:25:02 -08:00
9612e4d4e9 Removes unnecessary logo refresh logic. 2023-12-22 10:30:28 -08:00
4b938db0c1 refresh = true when logo is updated 2023-12-22 10:28:14 -08:00
b0a079dce9 Merge pull request #3592 from sbwalker/dev
refactor logic related to domain filtering for emails during external login
2023-12-21 15:55:07 -05:00
52069f35c5 refactor logic related to domain filtering for emails during external login 2023-12-21 15:54:46 -05:00
140535d875 Update README.md 2023-12-21 12:50:13 -05:00
611084d00c Merge pull request #3590 from oqtane/master
5.0.1 Release
2023-12-21 12:38:37 -05:00
1b7c810eeb Merge pull request #3589 from oqtane/dev
5.0.1 Release
2023-12-21 12:38:08 -05:00
dd2a698147 Refreshes settings page if logo changes. 2023-12-20 14:17:23 -08:00
e99df58bce Merge pull request #3585 from sbwalker/dev
add an AllowRichText parameter to the RichTextEditor component and add logic to handle JS Interop failures
2023-12-20 16:59:06 -05:00
70139221ab add an AllowRichText parameter to the RichTextEditor component and add logic to handle JS Interop failures 2023-12-20 16:58:46 -05:00
5d8d2b4a34 Merge pull request #3579 from sbwalker/dev
ensure database provider assemblies are included in Publish folder
2023-12-19 16:54:25 -05:00
f59f322226 ensure database provider assemblies are included in Publish folder 2023-12-19 16:54:11 -05:00
acca3f37b5 Merge pull request #3577 from sbwalker/dev
remove spaces from file extensions
2023-12-19 14:30:30 -05:00
0de62f620d remove spaces from file extensions 2023-12-19 14:30:18 -05:00
351c4a00e9 Merge pull request #3576 from sbwalker/dev
prepare for 5.0.1 release
2023-12-19 12:51:58 -05:00
b048d81ac0 prepare for 5.0.1 release 2023-12-19 12:51:44 -05:00
b9c9a2b75f Merge pull request #3575 from sbwalker/dev
add defensive logic to Alias.Path, improve new GetAlias method
2023-12-19 08:41:49 -05:00
4cea22d813 add defensive logic to Alias.Path, improve new GetAlias method 2023-12-19 08:41:36 -05:00
edad4e7d35 Merge pull request #3572 from thabaum/patch-5
Sets Logo max height to 90px plus padding 5px right and left.
2023-12-19 08:02:09 -05:00
e28acd8d2d Merge pull request #3574 from sbwalker/dev
handle loading/saving of File Extensions
2023-12-19 07:40:01 -05:00
86feaff82f handle loading/saving of File Extensions 2023-12-19 07:39:48 -05:00
5f747db224 Logo max-height and padding 2023-12-18 14:12:26 -08:00
ccda41e18e Logo max-height 90px, Padding 5px L/R 2023-12-18 14:11:29 -08:00
2bb83c6532 Revert app logo css changes 2023-12-18 14:10:23 -08:00
ec59faba8c Merge pull request #3573 from sbwalker/dev
add database provider projects to Oqtane.sln
2023-12-18 16:31:06 -05:00
c5d8c44b81 add database provider projects to Oqtane.sln 2023-12-18 16:30:49 -05:00
7a4e4629e5 Logo max height 90px 2023-12-18 13:03:19 -08:00
4d3dd95a60 Merge pull request #3568 from sbwalker/dev
add additional SetAlias overload
2023-12-18 15:07:20 -05:00
713021359e add additional SetAlias overload 2023-12-18 15:07:07 -05:00
927d2c36e8 Merge pull request #3566 from sbwalker/dev
abstract padding logic - don't repeat
2023-12-18 09:58:44 -05:00
afc6368915 abstract padding logic - don't repeat 2023-12-18 09:58:30 -05:00
3f604ad7b5 Merge pull request #3565 from sbwalker/dev
fix #3556 - pad token secret to 32 characters to resolve IDX1-720, change id of "secret" input to reduce chance of form autocomplete causing issues
2023-12-18 09:51:43 -05:00
c5d4e237ad fix #3556 - pad token secret to 32 characters to resolve IDX1-720, change id of "secret" input to reduce chance of form autocomplete causing issues 2023-12-18 09:51:18 -05:00
0b50b21779 Merge pull request #3559 from thabaum/patch-3
Correct formatting of _pagesWithModules declaration
2023-12-18 08:01:44 -05:00
cafc70f1c9 Correct formatting of _pagesWithModules declaration 2023-12-15 10:47:41 -08:00
b4377c346f Merge pull request #3558 from sbwalker/dev
modify module and theme template release.cmd to remove old nupkg files before packaging
2023-12-15 11:08:24 -05:00
7c206af757 modify module and theme template release.cmd to remove old nupkg files before packaging 2023-12-15 11:08:05 -05:00
6212d0a052 Merge pull request #3557 from sbwalker/dev
a simple dependency manager for assemblies
2023-12-15 11:06:01 -05:00
8909822aea a simple dependency manager for assemblies 2023-12-15 11:05:48 -05:00
5fc0964f73 Merge pull request #3555 from sbwalker/dev
suppress compiler warnings for internal Entity Framework Core API usage and Analyzer 'Microsoft.AspNetCore.Analyzers.WebApplicationBuilder.WebApplicationBuilderAnalyzer' (.NET8)
2023-12-14 15:23:04 -05:00
7725559a44 suppress compiler warnings for internal Entity Framework Core API usage and Analyzer 'Microsoft.AspNetCore.Analyzers.WebApplicationBuilder.WebApplicationBuilderAnalyzer' (.NET8) 2023-12-14 15:22:43 -05:00
03414a58e9 Merge pull request #3553 from sbwalker/dev
eliminate database provider nuget packages
2023-12-14 14:32:32 -05:00
ade0419bf6 eliminate database provider nuget packages 2023-12-14 14:32:19 -05:00
9d646b2eed Merge pull request #3552 from sbwalker/dev
ignore Blazor framework requests
2023-12-13 18:25:34 -05:00
0d718a5ca2 ignore Blazor framework requests 2023-12-13 18:25:21 -05:00
78c8b36dfa Merge pull request #3551 from sbwalker/dev
remove unecessary resource key
2023-12-13 13:34:24 -05:00
b5ca0874fa remove unecessary resource key 2023-12-13 13:34:08 -05:00
e209becff9 Merge pull request #3548 from leigh-pointer/ModuleMangPages
Module Management Ehancement - show where modules are used.
2023-12-13 11:22:22 -05:00
652d42aa6b Rework
Not to display the number of instances of the module on those pages.
Name the tab "Pages".
2023-12-13 17:19:19 +01:00
058a11597f Merge pull request #3550 from sbwalker/dev
fix regression issue
2023-12-13 11:18:44 -05:00
dd73d6e19a fix regression issue 2023-12-13 11:18:32 -05:00
3793f618a8 Merge pull request #3549 from sbwalker/dev
HTML encode notifications sent by non-admins to prevent HTML injection
2023-12-13 10:07:43 -05:00
6621983a9c HTML encode notifications sent by non-admins to prevent HTML injection 2023-12-13 10:07:21 -05:00
e0b0302f5a Check for Deleted Pageds 2023-12-12 22:56:02 +01:00
b02584bec6 Enhancment to the Module Managment to show where module is used.
Added a new tab that lists all the pages where there is a module instance with the count of the number of instances.
This helps when making a decision to delete the module from the framework.
2023-12-12 22:28:18 +01:00
c832d61409 Merge pull request #3547 from sbwalker/dev
set authentication cookie to HttpOnly
2023-12-12 15:56:30 -05:00
ac701f28b5 set authentication cookie to HttpOnly 2023-12-12 15:56:16 -05:00
53032140e7 Merge pull request #3546 from sbwalker/dev
security improvement - ensure returnurl is a relativre path
2023-12-12 15:55:03 -05:00
3c7633564f security improvement - ensure returnurl is a relativre path 2023-12-12 15:54:52 -05:00
43eae40404 Merge pull request #3545 from sbwalker/dev
add support for root sitemap.xml and robots.txt
2023-12-12 14:50:21 -05:00
e34b1b54d5 add support for root sitemap.xml and robots.txt 2023-12-12 14:50:08 -05:00
0658a7de0d Merge pull request #3544 from sbwalker/dev
comsider name and email claim values as optional
2023-12-12 14:04:08 -05:00
9e0a4dfac8 comsider name and email claim values as optional 2023-12-12 14:03:47 -05:00
82034ade90 Merge pull request #3543 from sbwalker/dev
modify #3528 so that it only saves the ImagesFiles and UploadableFiles if they are different than the default - otherwise it sets them to blank. This provides forward compatibility if the default values are updated in future framework versions.
2023-12-12 13:52:03 -05:00
b979203e12 modify #3528 so that it only saves the ImagesFiles and UploadableFiles if they are different than the default - otherwise it sets them to blank. This provides forward compatibility if the default values are updated in future framework versions. 2023-12-12 13:51:41 -05:00
c9a368f13a Merge pull request #3542 from sbwalker/dev
move message into file upload region
2023-12-12 13:39:52 -05:00
cfabf22fef move message into file upload region 2023-12-12 13:39:37 -05:00
61aef77916 Merge pull request #3541 from sbwalker/dev
refactor fix for #3539 to avoid string comparison
2023-12-12 13:32:45 -05:00
8b6c6beceb refactor fix for #3539 to avoid string comparison 2023-12-12 13:32:33 -05:00
4688e49454 Merge pull request #3540 from leigh-pointer/LoginURL
Fix #3539 for Multiple click on login button
2023-12-12 13:16:16 -05:00
76cc28b215 Merge pull request #3535 from rcpacheco/rcp_manage_language
Edit languages to set default.
2023-12-12 13:02:17 -05:00
467e5423d2 Fix #3539 for Multiple click on login button
Updated the LoginBase, if the URI doesn't contain the login URL then the NavigationManager is updated.
2023-12-12 07:25:35 +01:00
422bf7b689 Edit languages to set default. 2023-12-07 18:12:49 -06:00
1d230bd4aa Merge pull request #3533 from sbwalker/dev
fix issue where the list of containers was not being refreshed when the theme was changed
2023-12-05 16:57:42 -05:00
029850842b fix issue where the list of containers was not being refreshed when the theme was changed 2023-12-05 16:57:22 -05:00
cc65555c3d minor fix to routing 2023-12-05 12:17:02 -08:00
3b090396a4 Merge pull request #3532 from sbwalker/dev
added HybridEnabled field to Site table to indicate if .NET MAUI hybrid applications can be integrated
2023-12-04 16:35:24 -05:00
2e4656ae8b added HybridEnabled field to Site table to indicate if .NET MAUI hybrid applications can be integrated 2023-12-04 16:35:03 -05:00
ebce63baa4 Merge pull request #3531 from sbwalker/dev
add generic Result model for leveraging Result pattern
2023-12-04 15:41:19 -05:00
08f691ee0d add generic Result model for leveraging Result pattern 2023-12-04 15:41:00 -05:00
7550a19951 Merge pull request #3528 from leigh-pointer/FileExtentions
File Extension management - site wide. Fix for #3493
2023-12-04 15:16:42 -05:00
daeb76df11 Corrected the IsPrivate 2023-12-04 17:26:37 +01:00
31315e5ba6 Merge pull request #3530 from sbwalker/dev
allow AddModuleMessage to support displaying the message at the bottom of the module instance
2023-12-04 09:57:10 -05:00
e4e1fa6a4c allow AddModuleMessage to support displaying the message at the bottom of the module instance 2023-12-04 09:55:53 -05:00
6e36312be8 Update Site with ImageFiles and UploadableFiles 2023-12-04 09:07:11 +01:00
9cc7ba1d82 Merge branch 'oqtane:dev' into FileExtentions 2023-12-04 08:15:49 +01:00
9182001147 Merge pull request #3529 from sbwalker/dev
invalidate client assemblies cache when site is updated
2023-12-03 10:27:53 -05:00
5d1510083e invalidate client assemblies cache when site is updated 2023-12-03 10:27:33 -05:00
7035f4cc1f File Extension management - site wide.
I have added to the site settings file extension management.
The Constants remain for backward compatibility.
If the extensions are not updated then the Constant will be used.
2023-12-01 21:09:33 +01:00
da826b2a22 Merge pull request #3527 from sbwalker/dev
optimize assembly loading performance
2023-12-01 14:54:56 -05:00
a152d8664d optimize assembly loading performance 2023-12-01 14:54:44 -05:00
6ad75d963a Merge pull request #3526 from sbwalker/dev
only allow download of assemblies when using WebAssembly
2023-12-01 14:38:32 -05:00
e92d34a9e3 only allow download of assemblies when using WebAssembly 2023-12-01 14:38:16 -05:00
768066db58 Merge pull request #3525 from leigh-pointer/Retention
Retention controls and data should be number / int not string
2023-12-01 12:19:48 -05:00
886b63e55b Retention controls and data should be number / int not string
The Retention input controls in Log, Visitors and Notifications allowed text to be saved.  Modified all controls to accept only number.
2023-12-01 18:05:52 +01:00
3c7ee65b7d Merge pull request #3523 from beolafsen/dev
Extend the Section component  with "IsVisible" parameter
2023-12-01 08:50:19 -05:00
0e060c4564 Extend the Section component with "Visible" parameter 2023-12-01 07:34:17 +01:00
3e127dbd9c Merge pull request #3522 from sbwalker/dev
remove Blazor Hybrid from Hosting Models selection as it is not actually a hosting model
2023-11-30 17:19:18 -05:00
ad66d14a1b remove Blazor Hybrid from Hosting Models selection as it is not actually a hosting model 2023-11-30 17:18:37 -05:00
5db61b78ea Merge pull request #3518 from sbwalker/dev
add defensive logic to handle scenario where a tenant connection string does not exist in appsettings.json
2023-11-29 17:32:08 -05:00
85f9597f2c add defensive logic to handle scenario where a tenant connection string does not exist in appsettings.json 2023-11-29 17:31:51 -05:00
73aca22605 Merge pull request #3517 from sbwalker/dev
suppress logging for resized image files which no longer exist
2023-11-29 13:59:06 -05:00
077343ca20 suppress logging for resized image files which no longer exist 2023-11-29 13:58:52 -05:00
c76946c770 Merge pull request #3516 from sbwalker/dev
update SQLite and PostgreSQL to latest packages
2023-11-29 13:29:17 -05:00
2344a49260 update SQLite and PostgreSQL to latest packages 2023-11-29 13:28:53 -05:00
65f463dbbd Merge pull request #3471 from PfaffIC/dev-loginauthcookie
Added auth cookie expiration for external login via OAuth2.
2023-11-29 13:22:39 -05:00
6e100a70b9 Merge pull request #3510 from markdav-is/patch-4
Update _Host.cshtml.cs to account for fully qualified type names in theme resources
2023-11-29 13:21:39 -05:00
77650ebe09 Merge pull request #3515 from sbwalker/dev
refactor alwaysremember logic for consistency
2023-11-29 13:19:59 -05:00
cdba2bd9e2 refactor alwaysremember logic for consistency 2023-11-29 13:19:45 -05:00
e84cc92fcd Merge pull request #3514 from sbwalker/dev
add ClaimsPrincipal extension methods
2023-11-29 13:02:10 -05:00
a2890948bb add ClaimsPrincipal extension methods 2023-11-29 13:01:54 -05:00
f2e1ebef45 Merge pull request #3513 from sbwalker/dev
user identity improvements
2023-11-29 10:42:50 -05:00
3c33614115 user identity improvements 2023-11-29 10:42:23 -05:00
fcc4b1e8ee Merge pull request #3511 from sbwalker/dev
include Review Claims option in External Login for troubleshooting settings
2023-11-27 15:37:51 -05:00
c8ac4ec1e8 include a more detailed error message for tenant database migration issues 2023-11-27 15:35:58 -05:00
93ab8b88d4 include Review Claims option in External Login for troubleshooting settings 2023-11-27 15:07:48 -05:00
cc12c302e3 Update _Host.cshtml.cs
Noticed some spaces showing up in theme resources and tracked it down to this line.  Wrapping the name in a call to Utilities.GetTypeName cleared things up.
2023-11-26 18:13:41 -08:00
73941ca30e Merge pull request #3506 from sbwalker/dev
remove InstallDatabase method as it is no longer required now that all database providers are installed automatically
2023-11-22 16:10:03 -05:00
f963711820 remove InstallDatabase method as it is no longer required now that all database providers are installed automatically 2023-11-22 15:53:25 -05:00
1a0a301fb6 Merge pull request #3505 from sbwalker/dev
change terminology to Uninstall rather than Delete in Module Definitions and Themes - to better describe the action
2023-11-22 15:44:25 -05:00
f87a9b7aae change terminology to Uninstall rather than Delete in Module Definitions and Themes - to better describe the action 2023-11-22 15:44:07 -05:00
f18f0bc762 Merge pull request #3504 from sbwalker/dev
only display Authorization Response Type option for OpenIDConnect and fix missing localization
2023-11-22 15:37:08 -05:00
c3b1bc6674 only display Authorization Response Type option for OpenIDConnect and fix missing localization 2023-11-22 15:36:49 -05:00
e9bb228528 Merge pull request #3503 from sbwalker/dev
prevent localized Microsoft.CodeAnalysis.*.resources.dll files from being included in release
2023-11-22 15:04:19 -05:00
a906957454 prevent localized Microsoft.CodeAnalysis.*.resources.dll files from being included in release 2023-11-22 15:04:01 -05:00
49d10337a1 Merge pull request #3502 from sbwalker/dev
add Update API validation to default module template
2023-11-22 14:55:07 -05:00
87c6c31f1f add Update API validation to default module template 2023-11-22 14:54:06 -05:00
5f3639e396 Merge pull request #3501 from sbwalker/dev
add additional validation logic to Update API methods to ensure model ID matches ID parameter
2023-11-22 14:47:53 -05:00
14d36ef8dc add additional validation logic to Update API methods to ensure model ID matches ID parameter 2023-11-22 14:47:28 -05:00
fc186f1718 Merge pull request #3496 from sbwalker/dev
ignore nuget packages
2023-11-21 15:41:23 -05:00
70aa93fe8d ignore nuget packages 2023-11-21 15:41:13 -05:00
901df22d39 Merge pull request #3495 from sbwalker/dev
add database provider packages back to wwwroot/Packages as they are needed when cloning a fresh instance of source from Github
2023-11-21 15:22:05 -05:00
cd0fe3d6d4 add database provider packages back to wwwroot/Packages as they are needed when cloning a fresh instance of source from Github 2023-11-21 15:21:44 -05:00
09f2c3f645 Merge pull request #3494 from sbwalker/dev
fix .NET upgrade issue related to database provider packages
2023-11-21 15:15:17 -05:00
116542d8e4 fix .NET upgrade issue related to database provider packages 2023-11-21 15:09:14 -05:00
ffae6e269b Merge pull request #3487 from sbwalker/dev
increase size of MaximumReceiveMessageSize for Blazor Server
2023-11-17 16:06:24 -05:00
2194dc0463 increase size of MaximumReceiveMessageSize for Blazor Server 2023-11-17 16:06:11 -05:00
63e3923349 Merge remote-tracking branch 'oqtane/dev' into dev 2023-11-17 12:55:40 -08:00
da2d426137 Update README.md 2023-11-16 15:49:22 -05:00
8df7672624 Update README.md 2023-11-16 15:15:34 -05:00
b9dba61c97 Update README.md 2023-11-16 15:07:53 -05:00
1872a1a77c Merge pull request #3483 from oqtane/master
Merge pull request #3482 from oqtane/dev
2023-11-16 15:00:22 -05:00
cf57bad7fa Merge pull request #3482 from oqtane/dev
8.0.0 Release
2023-11-16 15:00:04 -05:00
7e956894ee Merge pull request #3477 from sbwalker/dev
fix warning in MySQL provider, update Database provider packages to official .NET 8 release, add Oqtane.Licensing
2023-11-15 20:49:33 -05:00
f78046d4c1 fix warning in MySQL provider, update Database provider packages to official .NET 8 release, add Oqtane.Licensing 2023-11-15 20:49:07 -05:00
beb09cbf4a Merge pull request #3476 from sbwalker/dev
add SiteState.IsPrerendering property back to avoid breaking change. New implementation relies on .NET 8 HttpContext CascadingParameter
2023-11-15 15:01:04 -05:00
6b2a5d7777 add SiteState.IsPrerendering property back to avoid breaking change. New implementation relies on .NET 8 HttpContext CascadingParameter 2023-11-15 15:00:34 -05:00
4b0d368222 Merge pull request #3475 from sbwalker/dev
migration to official .NET 8 release
2023-11-14 14:48:35 -05:00
5ab2f6ea3a migration to official .NET 8 release 2023-11-14 14:48:12 -05:00
f845bf5b25 Merge pull request #3472 from sbwalker/dev
fix #3454 - do not remove Oqtane.lLicensing assemblies during package uninstall
2023-11-13 13:16:56 -05:00
bb10d64d58 fix #3454 - do not remove Oqtane.lLicensing assemblies during package uninstall 2023-11-13 13:16:35 -05:00
96e8e9736f Added auth cookie expiration for external login via OAuth2.
Auth cookie expiration time ist set to value provided in Setting "LoginOptions:CookieExpiration" (if provided).
2023-11-13 11:28:58 +01:00
62472b97e6 Merge pull request #3469 from sbwalker/dev
update email address in AspNetUsers table when user email is modified
2023-11-10 16:13:37 -05:00
10b89ff00b update email address in AspNetUsers table when user email is modified 2023-11-10 16:13:24 -05:00
2d8339343f Merge pull request #3468 from sbwalker/dev
removed photo from Edit User as files cannot be written to other users folders
2023-11-10 15:59:02 -05:00
9ddd88b5d0 removed photo from Edit User as files cannot be written to other users folders 2023-11-10 15:58:43 -05:00
614ec645c6 Merge pull request #3467 from sbwalker/dev
use appropriate bootstrap classes
2023-11-10 15:40:32 -05:00
893ffc48dc use appropriate bootstrap classes 2023-11-10 15:40:20 -05:00
7bddb70f11 Merge pull request #3466 from sbwalker/dev
add new user settings to RESX file
2023-11-10 15:19:13 -05:00
9d4a38e560 add new user settings to RESX file 2023-11-10 15:18:59 -05:00
9d20b31585 Merge pull request #3465 from sbwalker/dev
fix #3399 - set defaults for all dropdowns in Add Site
2023-11-10 15:05:51 -05:00
fb8838375f fix #3399 - set defaults for all dropdowns in Add Site 2023-11-10 15:05:39 -05:00
dead4e3f85 Merge pull request #3464 from sbwalker/dev
fix #3420 - auto create user folder for Host user if it does not exist for site
2023-11-10 13:49:31 -05:00
9c833a8a95 fix #3420 - auto create user folder for Host user if it does not exist for site 2023-11-10 13:49:11 -05:00
0b90794bca Merge pull request #3463 from sbwalker/dev
move visitor tracking after url mapping and 404 handling
2023-11-10 13:11:30 -05:00
fd89757814 move visitor tracking after url mapping and 404 handling 2023-11-10 13:00:57 -05:00
5eedc312c8 Merge pull request #3462 from PfaffIC/dev-loginauthcookie
Added login cookie expiration time functionality.
2023-11-10 07:48:47 -05:00
36c1cc5e0c Added functinality to always remember user login.
Added functinality to always remember user login. Provides the option to force login cookie expiration and dont fallback on the session timespan that is used as default when users dont choose the option 'Remember me'.
2023-11-09 16:29:09 +01:00
0b4cdea9dd Added functinality to declare custom login cookie expiration time.
Added login cookie expiration time. Added setting in user settings to declare custom cookie expiration time. Cookie expiration time overwrites default expiration time of 14 days (if not session timespan is used).
2023-11-09 16:15:53 +01:00
12172168f6 Merge pull request #3460 from sbwalker/dev
improve upload time estimate calculations and limit polling attempts
2023-11-07 15:14:13 -05:00
c79aa49252 improve upload time estimate calculations and limit polling attempts 2023-11-07 15:13:33 -05:00
b869308bf4 Merge pull request #3459 from sbwalker/dev
fix #3438 - remove IsPrerendering property as it is not used, and remove reference to HttpContext
2023-11-07 13:52:30 -05:00
7a748bd142 fix #3438 - remove IsPrerendering property as it is not used, and remove reference to HttpContext 2023-11-07 13:49:54 -05:00
d11669e613 Merge pull request #3457 from oqtane/net8
Merging net8 branch into dev in preparation for Oqtane 5.0 release next week
2023-11-06 15:04:53 -05:00
b5108b938c Merge pull request #3447 from thabaum/net8-Admin-Profile-Edit-Validation
Admin\Profiles\Edit.razor: Form Validation For Rows, Length and Order - Adds Rows Resource Data - Issues #3426,  #3446
2023-10-30 09:12:27 -04:00
049d510536 Updates Order/Rows/Length min/max values 2023-10-26 14:01:27 -07:00
113f7b18a6 Replaces maxLength with max for input type number 2023-10-25 09:01:41 -07:00
65b248c3cf min="1" for "Rows" 2023-10-25 06:18:00 -07:00
1698996ac3 Adds "Rows" Resource Data 2023-10-24 16:12:19 -07:00
2ae47f2375 Adds type="number" Form Input Validation 2023-10-24 16:10:12 -07:00
6733d12e81 Merge pull request #3445 from sbwalker/net8
added Verify Existing Users? option to User Management - External Login Setting
2023-10-24 14:31:59 -04:00
8b5109e32f added Verify Existing Users? option to User Management - External Login Setting 2023-10-24 14:28:14 -04:00
7b651d56b1 Merge pull request #3444 from sbwalker/net8
if site login is disabled redirect Login to external identity provider
2023-10-24 13:49:09 -04:00
23b9b8aaf6 if site login is disabled redirect Login to external identity provider 2023-10-24 13:46:25 -04:00
8d9fb43828 Merge pull request #3443 from sbwalker/net8
fixes to notifications UI in user profile
2023-10-24 08:41:20 -04:00
0d1be72fdb fixes to notifications UI in user profile 2023-10-24 08:40:26 -04:00
ce102a2af6 Merge pull request #3436 from sbwalker/net8
complete fix for #3427 in User Profile component
2023-10-23 12:17:21 -04:00
dda6071bbc complete fix for #3427 in User Profile component 2023-10-23 12:16:52 -04:00
0c4809bb16 Merge pull request #3435 from sbwalker/net8
Fix spelling mistake "notififications"
2023-10-23 11:36:37 -04:00
4b87c5e80e Fix spelling mistake "notififications" 2023-10-23 11:36:03 -04:00
b8fe9b9074 Merge pull request #3425 from thabaum/net8-UserProfile-Index-Fix
UserProfile/Index.razor: Notifications Formatting and No Notifications Message - Fixes #3413, #3415
2023-10-23 11:33:31 -04:00
bc8b18cea8 Merge pull request #3434 from sbwalker/net8
fix #3427 - profile validation for User Management (Add/Edit)
2023-10-23 11:25:40 -04:00
20fdd3e891 fix #3427 - profile validation for User Management (Add/Edit) 2023-10-23 11:24:22 -04:00
ff9147487f Merge pull request #3424 from thabaum/net8-UserProfile-View-Fix
UserProfile/View.razor: Sets Input Classes to col-sm-9, Disables Reply When Notification From is System or Blank (empty)
2023-10-23 11:22:15 -04:00
af494f3b5e Merge pull request #3423 from thabaum/net8-Models-Profile-Fix
Oqtane.Server\Repository\SiteRepository.cs: Sets Rows Default Value Equal To 1.
2023-10-23 11:20:58 -04:00
f68d26317d Removes Biography 2023-10-21 15:12:15 -07:00
5b881f7c77 Disable Reply Button When From is System or Emtpy 2023-10-21 13:11:02 -07:00
fe5efff255 Adds Biography and Rows Profile Settings to Create Site 2023-10-21 10:36:09 -07:00
46d18a642c Rows property set to no default 2023-10-21 10:32:01 -07:00
c00012f28b class= 2023-10-20 21:57:42 -07:00
d0050f7d59 Updates Localization of No Notifications Messages 2023-10-20 21:39:19 -07:00
f3a4881261 No notification messages. 2023-10-20 21:38:06 -07:00
1728909964 Adds Localization To No Notification Messages 2023-10-20 21:34:43 -07:00
f6e7460b24 Fix Formatting + Add No Notifictions Message 2023-10-20 21:31:23 -07:00
351829888f Fix Columns Format 2023-10-20 21:25:27 -07:00
e520c30ade Rows Property Default Equals 1 2023-10-20 21:18:36 -07:00
99267ac2f0 Merge pull request #3409 from thabaum/thabaum-NET8-Development-Module-Theme-Templates
development module theme templates
2023-10-18 19:37:47 -04:00
6f1f7ef7fc Revert back to previous bootstrap version 2023-10-18 16:20:36 -07:00
d647e947e2 Removes unnecessary space 2023-10-18 15:52:22 -07:00
adef45c30f Removes unnecessary space 2023-10-18 15:51:58 -07:00
8b80859023 .NET 8 Update 2023-10-18 15:45:47 -07:00
907fff89c8 .NET 8 Update 2023-10-18 15:43:55 -07:00
ca532ffdaf .NET 8 Update 2023-10-18 15:43:13 -07:00
64ee842dc4 .NET 8 Update 2023-10-18 15:42:36 -07:00
9c0754a88d .NET 8 Update 2023-10-18 15:40:51 -07:00
3dac9e3dae .NET 8.0 Update 2023-10-18 15:38:51 -07:00
6963e667aa Update to version 5.0.0 2023-10-18 15:37:38 -07:00
af292b291b Updates to Bootstrap 5.3.2 2023-10-18 15:33:34 -07:00
918f75704e .NET 8 Update 2023-10-18 15:26:42 -07:00
6e258e5d0c .NET 8 Update 2023-10-18 15:23:06 -07:00
a8ea4ec085 .NET 8 Update 2023-10-18 15:22:22 -07:00
2f894af028 .NET 8 Update 2023-10-18 15:21:53 -07:00
dd400e1214 Version 5 2023-10-18 15:20:56 -07:00
f8a183bfdf .NET 8 Update 2023-10-18 15:06:44 -07:00
2404193b61 .NET 8 Ready 2023-10-18 15:04:07 -07:00
3ef11f5b26 Merge pull request #3408 from sbwalker/net8
fix compiler warning ASP0019: Use IHeaderDictionary.Append or the indexer to append or set headers.
2023-10-18 17:14:04 -04:00
30419cec12 fix compiler warning ASP0019: Use IHeaderDictionary.Append or the indexer to append or set headers. 2023-10-18 17:09:19 -04:00
162841feb8 Merge pull request #3405 from thabaum/net8
Removes unnecessary added space from upgrade to .NET 8
2023-10-18 16:18:32 -04:00
f910f63f8d Remove space 2023-10-18 13:14:52 -07:00
860cb75f8f Merge pull request #3404 from thabaum/net8
Remove default connection data
2023-10-18 16:14:27 -04:00
293be93b93 Remove default connection data 2023-10-18 12:55:39 -07:00
976e77b31e Merge pull request #3402 from sbwalker/net8
.NET 8 initial migration
2023-10-18 15:25:05 -04:00
9f28ee2982 .NET 8 initial migration 2023-10-18 15:22:53 -04:00
e6c1e48b86 Merge pull request #3396 from sbwalker/net8
test commit
2023-10-18 11:51:03 -04:00
2c2880199d test commit 2023-10-18 11:50:32 -04:00
c7f8737eeb Merge pull request #3392 from sbwalker/dev
resolve null reference exception in FileManager when ShowFiles = false
2023-10-17 15:12:06 -04:00
f3aea3108d resolve null reference exception in FileManager when ShowFiles = false 2023-10-17 15:11:51 -04:00
e4f8ad0f05 Update README.md 2023-10-16 15:05:12 -04:00
8b80f72313 Merge pull request #3386 from oqtane/master
4.0.6 Release
2023-10-16 15:00:27 -04:00
06ebce31ca Merge pull request #3385 from oqtane/dev
4.0.6 Release
2023-10-16 14:59:59 -04:00
59db8ba997 Merge pull request #3383 from sbwalker/dev
4.0.6 data provider packages
2023-10-16 09:08:17 -04:00
df37d4aa7f 4.0.6 data provider packages 2023-10-16 09:08:03 -04:00
fd9935c800 Merge pull request #3382 from sbwalker/dev
prepare for 4.0.6 release
2023-10-16 08:43:42 -04:00
c057430488 prepare for 4.0.6 release 2023-10-16 08:43:31 -04:00
767fa78e22 Merge pull request #3380 from sbwalker/dev
resolve issue in making Pager search work with sorting
2023-10-16 08:03:42 -04:00
a0e289dcd6 resolve issue in making Pager search work with sorting 2023-10-16 08:03:31 -04:00
c62d147254 Merge pull request #3375 from leigh-pointer/AllowPunctuation
Module Creator allow punctuation in Description field
2023-10-13 08:46:15 -04:00
f739bee353 Merge pull request #3376 from leigh-pointer/BootswatchThemeIssue
Fix for #3374 Backward compatability
2023-10-13 08:46:03 -04:00
db4dfb69fb Merge pull request #3377 from sbwalker/dev
improve Pager search to support properties on child objects
2023-10-13 08:39:23 -04:00
9729a5ef16 improve Pager search to support properties on child objects 2023-10-13 08:39:02 -04:00
6f12818352 Fix for #3374 Backward compatability
Fixes the issue in the Language selector.
2023-10-13 14:06:21 +02:00
75fc318da0 Module Creator all punctuation in description
Modified the Regex to all punctuation in the description.
2023-10-13 11:50:00 +02:00
acf71cc2c2 Merge pull request #3370 from leigh-pointer/LanguageAlignment
Language Selector Alignment fix  #3368
2023-10-12 11:10:47 -04:00
42efe10473 Merge pull request #3372 from sbwalker/dev
optimize Pager search to remove redundant AllowSearch parameter and avoid consuming memory when not in use
2023-10-12 11:10:35 -04:00
b77e72880b optimize Pager search to remove redundant AllowSearch parameter and avoid consuming memory when not in use 2023-10-12 11:10:14 -04:00
297c1524b4 Language Selector Alignment fix #3368
Themes fixed also
2023-10-11 15:48:05 +02:00
6140743769 Merge pull request #3352 from Rodien/dev
Introduce a dropdown menu for authorization response types
2023-10-11 09:08:48 -04:00
d5ca700828 Merge pull request #3366 from sbwalker/dev
change name of RESX key and value to reflect purpose
2023-10-10 10:33:39 -04:00
a7e1fe76c3 change name of RESX key and value to reflect purpose 2023-10-10 10:33:11 -04:00
f6c55279d1 Merge pull request #3364 from leigh-pointer/PagerSearch
Pager Search Localization
2023-10-10 10:25:47 -04:00
826f4835bb Merge branch 'dev' into PagerSearch 2023-10-10 10:25:37 -04:00
119a28def1 Pager Search Localization
Localization is now referencing the Shared Resources
2023-10-10 14:33:16 +02:00
c1ffb8bc33 Merge pull request #3365 from sbwalker/dev
use SharedLocalizer in Pager
2023-10-10 08:07:21 -04:00
60cc9d14af use SharedLocalizer in Pager 2023-10-10 08:07:07 -04:00
7cf4f8fdaa Pager Search Localization
Localized the new Search Buttons
Added a Localized Placeholder that will display what columns are being searched.
2023-10-10 11:28:57 +02:00
1b84e83061 Merge pull request #3363 from sbwalker/dev
add Search capability to Pager and include in management UIs
2023-10-09 16:59:54 -04:00
b0d2ee8760 add Search capability to Pager and include in management UIs 2023-10-09 16:59:36 -04:00
2022432d35 Merge pull request #3362 from sbwalker/dev
Add Rows option to Profile Management. Improve Profile validation feedback. Fix Add User so that profile Options are supported.
2023-10-09 14:27:24 -04:00
c0ed335d84 Add Rows option to Profile Management. Improve Profile validation feedback. Fix Add User so that profile Options are supported. 2023-10-09 14:26:56 -04:00
4964562866 Merge pull request #3361 from sbwalker/dev
include Pane in Module Settings
2023-10-09 13:19:00 -04:00
f78dc443ad include Pane in Module Settings 2023-10-09 13:18:43 -04:00
56b47db778 Merge pull request #3360 from sbwalker/dev
allow module to be inserted at top of pane
2023-10-09 12:58:15 -04:00
2d4bf17b28 allow module to be inserted at top of pane 2023-10-09 12:58:01 -04:00
3b1819c68d Merge pull request #3359 from sbwalker/dev
optimize UrlCombine method
2023-10-09 12:00:51 -04:00
575bbdb53b optimize UrlCombine method 2023-10-09 12:00:34 -04:00
2fa7482028 Introduce a dropdown menu in the 'External Login' settings area for authentication flow response types. 2023-10-03 09:00:53 +02:00
e5062317e2 Merge pull request #3347 from sbwalker/dev
do not show uploaded file name or delete button when multiple uploads are enabled
2023-09-29 11:49:05 -04:00
543f4fa3c2 do not show uploaded file name or delete button when multiple uploads are enabled 2023-09-29 11:48:45 -04:00
49cdf69815 Merge pull request #3344 from Mostafa-Moafi/dev
Fixed issue #3282
2023-09-28 15:36:00 -04:00
04196a1a19 Merge pull request #3346 from sbwalker/dev
display uploaded file name in FileManager when ShowFiles = false
2023-09-28 15:35:26 -04:00
b8622b8708 display uploaded file name in FileManager when ShowFiles = false 2023-09-28 15:35:13 -04:00
a2feca0ba3 Fixed Bug #3282 2023-09-28 19:23:31 +03:30
ae6c6a75b2 Merge pull request #3342 from sbwalker/dev
style page names in Admin Dashboard so that they are always visible in Bootstrap themes
2023-09-28 07:51:05 -04:00
bd987e9531 style page names in Admin Dashboard so that they are always visible in Bootstrap themes 2023-09-27 16:26:59 -04:00
24d69fd820 Merge pull request #3341 from sbwalker/dev
include CopyLocalLockFileAssemblies property in Client project in Default Module Template
2023-09-27 16:11:46 -04:00
9e2fa8d7f1 include CopyLocalLockFileAssemblies property in Client project in Default Module Template 2023-09-27 16:11:29 -04:00
74ba2f7283 Merge pull request #3340 from sbwalker/dev
add hyperlinks to product logos
2023-09-27 16:09:30 -04:00
7603b5c63f add hyperlinks to product logos 2023-09-27 16:09:19 -04:00
03566afe66 Merge pull request #3339 from sbwalker/dev
fix UrlCombine so that it handles leading and trailing path delimiters and returns proper paths
2023-09-27 16:07:32 -04:00
3c2e314e2d fix UrlCombine so that it handles leading and trailing path delimiters and returns proper paths 2023-09-27 16:07:13 -04:00
1fcf08b5cd Update README.md 2023-09-26 14:06:18 -04:00
c13db89ed4 Merge pull request #3330 from sbwalker/dev
4.0.5 data provider packages
2023-09-26 14:03:19 -04:00
e68ae9e8a6 4.0.5 data provider packages 2023-09-26 14:03:06 -04:00
fb252d6db3 Merge pull request #3329 from oqtane/master
4.0.5 release
2023-09-26 13:59:55 -04:00
df959353d6 Merge pull request #3328 from oqtane/dev
4.0.5 release
2023-09-26 13:59:29 -04:00
fbc443483d Merge pull request #3327 from sbwalker/dev
prepare for 4.0.5
2023-09-26 11:35:05 -04:00
00f1dbc3dd prepare for 4.0.5 2023-09-26 11:34:52 -04:00
c6021ff012 Merge pull request #3326 from ijaz-saeed/dev
Empty _themetype check to avoid page crash
2023-09-26 10:23:02 -04:00
7a8cfcee35 Empty _themetype check to avoid page crash
without this check, admin dashboard -> Page Management -> Edit page
is crashing
2023-09-26 18:23:29 +05:00
c15586a1c4 Update README.md 2023-09-25 16:00:23 -04:00
531 changed files with 23194 additions and 9386 deletions

26
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,26 @@
---
name: Bug Report
about: Create a bug report to help us improve the product
title: "[BUG] "
labels: ''
assignees: ''
---
### Oqtane Info
Version - #.#.#
Render Mode - Static
Interactivity - Server
Database - SQL Server
### Describe the bug
### Expected Behavior
### Steps To Reproduce
### Anything else?

View File

@ -0,0 +1,20 @@
---
name: Enhancement Request
about: 'Suggest a product enhancement '
title: "[ENH] "
labels: ''
assignees: ''
---
### Oqtane Info
Version - #.#.#
Render Mode - Static
Interactivity - Server
Database - SQL Server
### Describe the enhancement
### Anything else?

13
.gitignore vendored
View File

@ -16,16 +16,23 @@ _ReSharper.Caches
Oqtane.Server/appsettings.json
Oqtane.Server/Data
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml
Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml
Oqtane.Server/Content
Oqtane.Server/Packages
Oqtane.Server/wwwroot/Content
Oqtane.Server/wwwroot/Packages/*.log
Oqtane.Server/wwwroot/Modules
Oqtane.Server/wwwroot/_content/*
!Oqtane.Server/wwwroot/_content/Placeholder.txt
Oqtane.Server/wwwroot/Modules/*
!Oqtane.Server/wwwroot/Modules/Oqtane.Modules.*
!Oqtane.Server/wwwroot/Modules/Templates
Oqtane.Server/wwwroot/Modules/Templates/*
!Oqtane.Server/wwwroot/Modules/Templates/External
Oqtane.Server/wwwroot/Themes
Oqtane.Server/wwwroot/Themes/*
!Oqtane.Server/wwwroot/Themes/Oqtane.Themes.*
!Oqtane.Server/wwwroot/Themes/Templates
Oqtane.Server/wwwroot/Themes/Templates/*
Oqtane.Server/wwwroot/Themes/Templates/External

24
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,24 @@
# Contributing to Oqtane
## How to Contribute
We track all of our issues on Github. If you want to contribute, everything starts with an issue. If you don't have an issue yet, you can add one. Then a core contributor will tag it as either an enhancement [ENH] or a bug [BUG]. Tagged issues are open for contribution.
## Use GitHub-flow process
- Make a comment on the issue that you intend to work on it and read all the comments to gain a full understanding.
- Fork the repository
- Create a new branch and update your comment on the issue with a llink to the branch
- Make your changes and commit them
- Push to the branch
- Create a pull request
## Reporting Bugs
- Check if the issue has already been reported.
- Open a new issue if it hasnt been reported.
## Requesting Features
- Use the feature request template in the Issues tab.
Thank you for contributing!

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018-2023 .NET Foundation
Copyright (c) 2018-2025 .NET Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,100 +0,0 @@
@using Microsoft.AspNetCore.Http
@inject IInstallationService InstallationService
@inject IJSRuntime JSRuntime
@inject SiteState SiteState
@inject IServiceProvider ServiceProvider
@if (_initialized)
{
@if (!_installation.Success)
{
<Installer />
}
else
{
@if (string.IsNullOrEmpty(_installation.Message))
{
<div style="@_display">
<CascadingAuthenticationState>
<CascadingValue Value="@PageState">
<SiteRouter Runtime="@Runtime" RenderMode="@RenderMode" VisitorId="@VisitorId" OnStateChange="@ChangeState" />
</CascadingValue>
</CascadingAuthenticationState>
</div>
}
else
{
<div class="app-alert">
@_installation.Message
</div>
}
}
}
@code {
[Parameter]
public string AntiForgeryToken { get; set; }
[Parameter]
public string Runtime { get; set; }
[Parameter]
public string RenderMode { get; set; }
[Parameter]
public int VisitorId { get; set; }
[Parameter]
public string RemoteIPAddress { get; set; }
[Parameter]
public string AuthorizationToken { get; set; }
private bool _initialized = false;
private string _display = "display: none;";
private Installation _installation = new Installation { Success = false, Message = "" };
private PageState PageState { get; set; }
private IHttpContextAccessor accessor;
protected override async Task OnParametersSetAsync()
{
SiteState.RemoteIPAddress = RemoteIPAddress;
SiteState.AntiForgeryToken = AntiForgeryToken;
SiteState.AuthorizationToken = AuthorizationToken;
accessor = (IHttpContextAccessor)ServiceProvider.GetService(typeof(IHttpContextAccessor));
if (accessor != null)
{
SiteState.IsPrerendering = !accessor.HttpContext.Response.HasStarted;
}
else
{
SiteState.IsPrerendering = true;
}
_installation = await InstallationService.IsInstalled();
if (_installation.Alias != null)
{
SiteState.Alias = _installation.Alias;
}
_initialized = true;
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
// prevents flash on initial page load
_display = "";
StateHasChanged();
}
}
private void ChangeState(PageState pageState)
{
PageState = pageState;
StateHasChanged();
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components.Authorization;
using Oqtane.Interfaces;
using Oqtane.Providers;
using Oqtane.Services;
using Oqtane.Shared;
@ -7,16 +8,17 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class OqtaneServiceCollectionExtensions
{
public static IServiceCollection AddOqtaneAuthorization(this IServiceCollection services)
public static IServiceCollection AddOqtaneAuthentication(this IServiceCollection services)
{
services.AddAuthorizationCore();
services.AddCascadingAuthenticationState();
services.AddScoped<IdentityAuthenticationStateProvider>();
services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<IdentityAuthenticationStateProvider>());
return services;
}
public static IServiceCollection AddOqtaneScopedServices(this IServiceCollection services)
public static IServiceCollection AddOqtaneClientScopedServices(this IServiceCollection services)
{
services.AddScoped<SiteState>();
services.AddScoped<IInstallationService, InstallationService>();
@ -49,6 +51,13 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddScoped<IUrlMappingService, UrlMappingService>();
services.AddScoped<IVisitorService, VisitorService>();
services.AddScoped<ISyncService, SyncService>();
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
services.AddScoped<ICookieConsentService, CookieConsentService>();
services.AddScoped<IOutputCacheService, OutputCacheService>();
// providers
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.TextAreaTextEditor>();
return services;
}

View File

@ -15,7 +15,7 @@
<div class="row">
<div class="mx-auto text-center">
<img src="oqtane-black.png" />
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 7)</div>
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 9)</div>
</div>
</div>
<hr class="app-rule" />
@ -69,16 +69,16 @@
<h2>@Localizer["ApplicationAdmin"]</h2><br />
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="username" HelpText="Provide a username for the primary user accountt" ResourceKey="Username">Username:</Label>
<Label Class="col-sm-3" For="username" HelpText="Provide a username for the primary user account" ResourceKey="Username">Username:</Label>
<div class="col-sm-9">
<input id="username" type="text" class="form-control" @bind="@_hostUsername" />
<input id="username" type="text" class="form-control" maxlength="256" @bind="@_hostUsername" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_passwordType" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
<input id="password" type="@_passwordType" class="form-control" maxlength="256" @bind="@_hostPassword" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglePassword</button>
</div>
</div>
@ -87,7 +87,7 @@
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
<div class="col-sm-9">
<div class="input-group">
<input id="confirm" type="@_confirmPasswordType" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
<input id="confirm" type="@_confirmPasswordType" class="form-control" maxlength="256" @bind="@_confirmPassword" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword" tabindex="-1">@_toggleConfirmPassword</button>
</div>
</div>
@ -95,7 +95,13 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="Provide the email address for the host user account" ResourceKey="Email">Email:</Label>
<div class="col-sm-9">
<input type="text" class="form-control" @bind="@_hostEmail" />
<input type="text" class="form-control" maxlength="256" @bind="@_hostEmail" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Provide the full name of the host user" ResourceKey="Name">Full Name:</Label>
<div class="col-sm-9">
<input type="text" class="form-control" maxlength="50" @bind="@_hostName" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -153,130 +159,134 @@
private string _toggleConfirmPassword = string.Empty;
private string _confirmPassword = string.Empty;
private string _hostEmail = string.Empty;
private string _hostName = string.Empty;
private List<SiteTemplate> _templates;
private string _template = Constants.DefaultSiteTemplate;
private bool _register = true;
private string _message = string.Empty;
private string _loadingDisplay = "display: none;";
private string _message = string.Empty;
private string _loadingDisplay = "display: none;";
protected override async Task OnInitializedAsync()
{
protected override async Task OnInitializedAsync()
{
// include CSS
var content = "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css\" integrity=\"sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==\" crossorigin=\"anonymous\" type=\"text/css\"/>";
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
SiteState.AppendHeadContent(content);
_togglePassword = SharedLocalizer["ShowPassword"];
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
_message = Localizer["Error.DbConfig.Load"];
}
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
_message = Localizer["Error.DbConfig.Load"];
}
}
private void LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
if (database != null)
{
_databaseConfigType = Type.GetType(database.ControlType);
DatabaseConfigComponent = builder =>
{
builder.OpenComponent(0, _databaseConfigType);
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
builder.CloseComponent();
};
}
}
private void LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
if (database != null)
{
_databaseConfigType = Type.GetType(database.ControlType);
DatabaseConfigComponent = builder =>
{
builder.OpenComponent(0, _databaseConfigType);
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
builder.CloseComponent();
};
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// include JavaScript
var interop = new Interop(JSRuntime);
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js", "sha512-VK2zcvntEufaimc+efOYi622VN5ZacdnufnmX7zIhCPmjhKnOi9ZDMtg1/ug5l183f19gG1/cBstPO4D8N/Img==", "anonymous", "", "head");
}
}
var interop = new Interop(JSRuntime);
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
}
}
private async Task Install()
{
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
private async Task Install()
{
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
{
if (await UserService.ValidatePasswordAsync(_hostPassword))
{
_loadingDisplay = "";
StateHasChanged();
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@") && !string.IsNullOrEmpty(_hostName))
{
var result = await UserService.ValidateUserAsync(_hostUsername, _hostEmail, _hostPassword);
if (result.Succeeded)
{
_loadingDisplay = "";
StateHasChanged();
Uri uri = new Uri(NavigationManager.Uri);
Uri uri = new Uri(NavigationManager.Uri);
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var config = new InstallConfig
{
DatabaseType = database.DBType,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostUsername = _hostUsername,
HostPassword = _hostPassword,
HostEmail = _hostEmail,
HostName = _hostUsername,
TenantName = TenantNames.Master,
IsNewTenant = true,
SiteName = Constants.DefaultSite,
Register = _register,
SiteTemplate = _template
};
var config = new InstallConfig
{
DatabaseType = database.DBType,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostUsername = _hostUsername,
HostPassword = _hostPassword,
HostEmail = _hostEmail,
HostName = _hostName,
TenantName = TenantNames.Master,
IsNewTenant = true,
SiteName = Constants.DefaultSite,
Register = _register,
SiteTemplate = _template,
RenderMode = RenderModes.Static,
Runtime = Runtimes.Server
};
var installation = await InstallationService.Install(config);
if (installation.Success)
{
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
}
else
{
_message = installation.Message;
_loadingDisplay = "display: none;";
}
}
else
{
_message = Localizer["Message.Password.Invalid"];
var installation = await InstallationService.Install(config);
if (installation.Success)
{
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
}
else
{
_message = installation.Message;
_loadingDisplay = "display: none;";
}
}
else
{
_message = string.Join("<br />", result.Errors.Select(i => !string.IsNullOrEmpty(i.Value) ? i.Value : Localizer[i.Key]));
}
}
else

View File

@ -12,9 +12,10 @@
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
string url = NavigateUrl(p.Path);
<div class="col-md-2 mx-auto text-center mb-3">
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>@SharedLocalizer[p.Name]
<div class="col-md-2 mx-auto text-center my-3">
<NavLink class="nav-link text-body" href="@url" Match="NavLinkMatch.All">
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>
<div class="lead">@((MarkupString)SharedLocalizer[p.Name].ToString().Replace(" ", "<br />"))</div>
</NavLink>
</div>
}
@ -26,6 +27,7 @@
private List<Page> _pages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
public override string RenderMode => RenderModes.Static;
protected override void OnInitialized()
{

View File

@ -4,6 +4,7 @@
@inject NavigationManager NavigationManager
@inject IFileService FileService
@inject IFolderService FolderService
@inject ISettingService SettingService
@inject IStringLocalizer<Add> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -80,6 +81,7 @@
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
if (_url == string.Empty || _folderId == -1)
@ -93,7 +95,7 @@
_name = _url.Substring(_url.LastIndexOf("/", StringComparison.Ordinal) + 1);
}
if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(_name).ToLower().Replace(".", "")))
if (!PageState.Site.UploadableFiles.Split(',').Contains(Path.GetExtension(_name).ToLower().Replace(".", "")))
{
AddModuleMessage(Localizer["Message.Download.InvalidExtension"], MessageType.Warning);
return;

View File

@ -40,10 +40,14 @@
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="SaveFile">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
@if (_name.ToLower().EndsWith(".zip"))
{
<button type="button" class="btn btn-primary mx-1" @onclick="UnzipFile">Unzip</button>
}
<br /><br />
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
</form>
}
@ -126,4 +130,18 @@
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
}
}
private async Task UnzipFile()
{
try
{
await FileService.UnzipFileAsync(_fileId);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Unzipping File {FileId} {Error}", _fileId, ex.Message);
AddModuleMessage(Localizer["Error.File.Unzip"], MessageType.Error);
}
}
}

View File

@ -8,66 +8,83 @@
@if (_folders != null)
{
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="parent" HelpText="Select the parent folder" ResourceKey="Parent">Parent: </Label>
<div class="col-sm-9">
<select id="parent" class="form-select" @bind="@_parentId" required>
@if (PageState.QueryString.ContainsKey("id"))
{
<option value="-1">&lt;@Localizer["NoParent"]&gt;</option>
}
@foreach (Folder folder in _folders)
{
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
</select>
<TabStrip>
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="parent" HelpText="Select the parent folder" ResourceKey="Parent">Parent: </Label>
<div class="col-sm-9">
<select id="parent" class="form-select" @bind="@_parentId" required>
@if (PageState.QueryString.ContainsKey("id"))
{
<option value="-1">&lt;@Localizer["NoParent"]&gt;</option>
}
@foreach (Folder folder in _folders)
{
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter the folder name" ResourceKey="Name">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_name" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="type" HelpText="Select the folder type. Private folders are only accessible by authorized users. Public folders can be accessed by all users" ResourceKey="Type">Type: </Label>
<div class="col-sm-9">
@if (PageState.QueryString.ContainsKey("id"))
{
<input id="type" class="form-control" readonly @bind="@_type" />
}
else
{
<select id="type" class="form-select" @bind="@_type" required>
<option value="@FolderTypes.Private">@Localizer[FolderTypes.Private]</option>
<option value="@FolderTypes.Public">@Localizer[FolderTypes.Public]</option>
</select>
}
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="capacity" HelpText="Enter the maximum folder capacity (in megabytes). Specify zero if the capacity is unlimited." ResourceKey="Capacity">Capacity: </Label>
<div class="col-sm-9">
<input id="capacity" class="form-control" @bind="@_capacity" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="cachecontrol" HelpText="Optionally provide a Cache-Control directive for this folder. For example 'public, max-age=60' indicates that files in this folder should be cached for 60 seconds. Please note that when caching is enabled, changes to files will not be immediately reflected in the UI." ResourceKey="CacheControl">Caching: </Label>
<div class="col-sm-9">
<input id="cachecontrol" class="form-control" @bind="@_cachecontrol" maxlength="50" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="imagesizes" HelpText="Optionally enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes (not recommended)." ResourceKey="ImageSizes">Image Sizes: </Label>
<div class="col-sm-9">
<input id="imagesizes" class="form-control" @bind="@_imagesizes" maxlength="512" />
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter the folder name" ResourceKey="Name">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_name" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="type" HelpText="Select the folder type. Private folders are only accessible by authorized users. Public folders can be accessed by all users" ResourceKey="Type">Type: </Label>
<div class="col-sm-9">
@if (PageState.QueryString.ContainsKey("id"))
{
<input id="type" class="form-control" readonly @bind="@_type" />
}
else
{
<select id="type" class="form-select" @bind="@_type" required>
<option value="@FolderTypes.Private">@Localizer[FolderTypes.Private]</option>
<option value="@FolderTypes.Public">@Localizer[FolderTypes.Public]</option>
</select>
}
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="imagesizes" HelpText="Enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes." ResourceKey="ImageSizes">Image Sizes: </Label>
<div class="col-sm-9">
<input id="imagesizes" class="form-control" @bind="@_imagesizes" maxlength="512" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="capacity" HelpText="Enter the maximum folder capacity (in megabytes). Specify zero if the capacity is unlimited." ResourceKey="Capacity">Capacity: </Label>
<div class="col-sm-9">
<input id="capacity" class="form-control" @bind="@_capacity" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<div class="col-sm-12">
<Label Class="col-sm-3" For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
@if (PageState.QueryString.ContainsKey("id"))
{
<br />
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
}
</form>
</TabPanel>
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
<div class="container">
<div class="row mb-1 align-items-center">
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" PermissionList="@_permissions" @ref="_permissionGrid" />
</div>
</div>
</div>
</form>
</TabPanel>
</TabStrip>
<br />
@if (!_isSystem)
{
<button type="button" class="btn btn-success" @onclick="SaveFolder">@SharedLocalizer["Save"]</button>
@ -79,12 +96,6 @@
@((MarkupString)"&nbsp;")
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
}
<br />
<br />
@if (PageState.QueryString.ContainsKey("id"))
{
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
}
}
@code {
@ -95,8 +106,9 @@
private int _parentId = -1;
private string _name;
private string _type = FolderTypes.Private;
private string _imagesizes = string.Empty;
private string _capacity = "0";
private string _cachecontrol = string.Empty;
private string _imagesizes = string.Empty;
private bool _isSystem;
private List<Permission> _permissions = null;
private string _createdBy;
@ -127,8 +139,9 @@
_parentId = folder.ParentId ?? -1;
_name = folder.Name;
_type = folder.Type;
_imagesizes = folder.ImageSizes;
_capacity = folder.Capacity.ToString();
_cachecontrol = folder.CacheControl;
_imagesizes = folder.ImageSizes;
_isSystem = folder.IsSystem;
_permissions = folder.PermissionList;
_createdBy = folder.CreatedBy;
@ -170,6 +183,7 @@
try
{
Folder folder;
if (_folderId != -1)
{
folder = await FolderService.GetFolderAsync(_folderId);
@ -179,8 +193,6 @@
folder = new Folder();
}
folder.SiteId = PageState.Site.SiteId;
if (_parentId == -1)
{
folder.ParentId = null;
@ -190,10 +202,19 @@
folder.ParentId = _parentId;
}
// check for duplicate folder names
if (_folders.Any(item => item.ParentId == folder.ParentId && item.Name == _name && item.FolderId != _folderId))
{
AddModuleMessage(Localizer["Message.Folder.Duplicate"], MessageType.Warning);
return;
}
folder.SiteId = PageState.Site.SiteId;
folder.Name = _name;
folder.Type = _type;
folder.ImageSizes = _imagesizes;
folder.Capacity = int.Parse(_capacity);
folder.CacheControl = _cachecontrol;
folder.ImageSizes = _imagesizes;
folder.IsSystem = _isSystem;
folder.PermissionList = _permissionGrid.GetPermissionList();

View File

@ -3,53 +3,92 @@
@inject NavigationManager NavigationManager
@inject IFolderService FolderService
@inject IFileService FileService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@if (_files != null)
@if (_files == null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<div class="col-sm-2">
<label class="control-label">@Localizer["Folder"] </label>
</div>
<div class="col-sm-6">
<select class="form-select" @onchange="(e => FolderChanged(e))">
@foreach (Folder folder in _folders)
{
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
</select>
</div>
<div class="col-sm-4">
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />&nbsp;
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />&nbsp;
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
<p>
<em>@SharedLocalizer["Loading"]</em>
</p>
}
else
{
<TabStrip>
<TabPanel Name="Files" Heading="Files" ResourceKey="Files">
<div class="row">
<div class="col-md mb-1">
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
</div>
<div class="col-md-8 mb-1">
<div class="input-group">
<span class="input-group-text">@Localizer["Folder"]:</span>
<select class="form-select" @onchange="(e => FolderChanged(e))">
@foreach (Folder folder in _folders)
{
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
}
</select>
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />&nbsp;
</div>
</div>
<div class="col-md mb-1 text-end">
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
</div>
</div>
</div>
</div>
<Pager Items="@_files">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["Modified"]</th>
<th>@Localizer["Type"]</th>
<th>@Localizer["Size"]</th>
</Header>
<Row>
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
<td><ActionDialog Header="Delete File" Message="@string.Format(Localizer["Confirm.File.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
<td><a href="@context.Url" target="_new">@context.Name</a></td>
<td>@context.ModifiedOn</td>
<td>@context.Extension.ToUpper() @SharedLocalizer["File"]</td>
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
</Row>
</Pager>
@if (_files.Count == 0)
{
<div class="text-center">@Localizer["NoFiles"]</div>
}
@if (_files.Count != 0)
{
<Pager Items="@_files" SearchProperties="Name">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["Modified"]</th>
<th>@Localizer["Type"]</th>
<th>@Localizer["Size"]</th>
</Header>
<Row>
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
<td><ActionDialog Header="Delete File" Message="@string.Format(Localizer["Confirm.File.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
<td><a href="@context.Url" target="_new">@context.Name</a></td>
<td>@context.ModifiedOn</td>
<td>@context.Extension.ToUpper() @SharedLocalizer["File"]</td>
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
</Row>
</Pager>
}
else
{
<div class="text-center">@Localizer["NoFiles"]</div>
}
</TabPanel>
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="imageExt" HelpText="Enter a comma separated list of image file extensions" ResourceKey="ImageExtensions">Image Extensions: </Label>
<div class="col-sm-9">
<input id="imageExt" spellcheck="false" class="form-control" @bind="@_imageFiles" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="uploadableFileExt" HelpText="Enter a comma separated list of uploadable file extensions" ResourceKey="UploadableFileExtensions">Uploadable File Extensions: </Label>
<div class="col-sm-9">
<input id="uploadableFileExt" spellcheck="false" class="form-control" @bind="@_uploadableFiles" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="maxChunkSize" HelpText="Files are split into chunks to streamline the upload process. Specify the maximum chunk size in MB (note that higher chunk sizes should only be used on faster networks)." ResourceKey="MaxChunkSize">Max Upload Chunk Size (MB): </Label>
<div class="col-sm-9">
<input id="maxChunkSize" type="number" min="1" max="10" step="1" class="form-control" @bind="@_maxChunkSize" />
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
</TabPanel>
</TabStrip>
}
@code {
@ -57,6 +96,10 @@
private int _folderId = -1;
private List<File> _files;
private string _imageFiles = string.Empty;
private string _uploadableFiles = string.Empty;
private int _maxChunkSize = 1;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnParametersSetAsync()
@ -70,6 +113,13 @@
_folderId = _folders[0].FolderId;
await GetFiles();
}
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_imageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
_imageFiles = (string.IsNullOrEmpty(_imageFiles)) ? Constants.ImageFiles : _imageFiles;
_uploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles);
_uploadableFiles = (string.IsNullOrEmpty(_uploadableFiles)) ? Constants.UploadableFiles : _uploadableFiles;
_maxChunkSize = int.Parse(SettingService.GetSetting(settings, "MaxChunkSize", "1"));
}
catch (Exception ex)
{
@ -114,4 +164,23 @@
AddModuleMessage(string.Format(Localizer["Error.File.Delete"], file.Name), MessageType.Error);
}
}
private async Task SaveSiteSettings()
{
try
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "ImageFiles", (_imageFiles != Constants.ImageFiles) ? _imageFiles.Replace(" ", "") : "", false);
settings = SettingService.SetSetting(settings, "UploadableFiles", (_uploadableFiles != Constants.UploadableFiles) ? _uploadableFiles.Replace(" ", "") : "", false);
settings = SettingService.SetSetting(settings, "MaxChunkSize", _maxChunkSize.ToString(), false);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
}
}
}

View File

@ -0,0 +1,19 @@
using Oqtane.Documentation;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Modules.Admin.Files
{
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "File Management",
Description = "File Management",
Version = Constants.Version,
Categories = "Admin",
ServerManagerType = "Oqtane.Modules.Admin.Files.Manager.FileManager, Oqtane.Server"
};
}
}

View File

@ -31,7 +31,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runs-every" HelpText="Select how often you want the job to run" ResourceKey="RunsEvery">Runs Every: </Label>
<div class="col-sm-9">
<input id="runs-every" class="form-control" @bind="@_interval" maxlength="4" required />
<input id="runs-every" class="form-control mb-1" @bind="@_interval" maxlength="4" required />
<select id="runs-every" class="form-select" @bind="@_frequency" required>
<option value="m">@Localizer["Minute(s)"]</option>
<option value="H">@Localizer["Hour(s)"]</option>
@ -45,7 +45,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label>
<div class="col-sm-9">
<input id="retention" class="form-control" @bind="@_retentionHistory" maxlength="4" required />
<input id="retention" type="number" min="0" step ="1" class="form-control" @bind="@_retentionHistory" maxlength="4" required />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -154,6 +154,11 @@
private async Task SaveJob()
{
if (!Utilities.ValidateEffectiveExpiryDates(_startDate, _endDate))
{
AddModuleMessage(Localizer["Message.StartEndDateError"], MessageType.Warning);
return;
}
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))

View File

@ -10,14 +10,11 @@
}
else
{
<ActionLink Action="Log" Class="btn btn-secondary" Text="View Logs" ResourceKey="ViewJobs" />
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">@Localizer["Refresh.Text"]</button>
<br />
<button type="button" class="btn btn-secondary" @onclick="Refresh">@Localizer["Refresh.Text"]</button>
<br />
<Pager Items="@_jobs">
<Pager Items="@_jobs" SearchProperties="Name">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
@ -27,9 +24,8 @@ else
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
<td><ActionDialog Header="Delete Job" Message="Are You Sure You Wish To Delete This Job?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteJob(context))" ResourceKey="DeleteJob" /></td>
<td><ActionLink Action="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
<td><ActionLink Action="Log" Text="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
<td>@context.Name</td>
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
@ -46,21 +42,25 @@ else
</td>
</Row>
</Pager>
<br />
<ActionLink Action="Log" Class="btn btn-secondary" Text="View All Logs" ResourceKey="ViewLogs" />
}
@code {
private List<Job> _jobs;
private List<Job> _jobs;
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
protected override async Task OnParametersSetAsync()
{
_jobs = await JobService.GetJobsAsync();
if (_jobs.Count == 0)
{
AddModuleMessage(string.Format(Localizer["Message.NoJobs"], NavigateUrl("admin/system")), MessageType.Warning);
}
}
protected override async Task OnInitializedAsync()
{
await GetJobs();
}
private async Task GetJobs()
{
_jobs = await JobService.GetJobsAsync();
}
private string DisplayStatus(bool isEnabled, bool isExecuting)
{
@ -112,22 +112,6 @@ else
return result;
}
private async Task DeleteJob(Job job)
{
try
{
await JobService.DeleteJobAsync(job.JobId);
await logger.LogInformation("Job Deleted {Job}", job);
_jobs = await JobService.GetJobsAsync();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Job {Job} {Error}", job, ex.Message);
AddModuleMessage(Localizer["Error.Job.Delete"], MessageType.Error);
}
}
private async Task StartJob(int jobId)
{
try
@ -164,7 +148,8 @@ else
private async Task Refresh()
{
_jobs = await JobService.GetJobsAsync();
StateHasChanged();
ShowProgressIndicator();
await GetJobs();
HideProgressIndicator();
}
}

View File

@ -10,6 +10,9 @@
}
else
{
<button type="button" class="btn btn-secondary" @onclick="Refresh">@Localizer["Refresh"]</button>
<br /><br />
<Pager Items="@_jobLogs">
<Header>
<th>@SharedLocalizer["Name"]</th>
@ -35,6 +38,11 @@ else
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
await GetJobLogs();
}
private async Task GetJobLogs()
{
_jobLogs = await JobLogService.GetJobLogsAsync();
@ -67,4 +75,11 @@ else
return status;
}
private async Task Refresh()
{
ShowProgressIndicator();
await GetJobLogs();
HideProgressIndicator();
}
}

View File

@ -1,7 +1,6 @@
@namespace Oqtane.Modules.Admin.Languages
@inherits ModuleBase
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@inject NavigationManager NavigationManager
@inject ILocalizationService LocalizationService
@inject ILanguageService LanguageService
@ -94,7 +93,6 @@ else
var language = new Language
{
SiteId = PageState.Page.SiteId,
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
Code = _code,
IsDefault = (_default == null ? false : Boolean.Parse(_default))
};
@ -130,9 +128,7 @@ else
{
var interop = new Interop(JSRuntime);
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
NavigationManager.NavigateTo(NavigationManager.Uri, true);
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360, true, "Lax");
}
}

View File

@ -0,0 +1,109 @@
@namespace Oqtane.Modules.Admin.Languages
@inherits ModuleBase
@using System.Globalization
@inject NavigationManager NavigationManager
@inject ILocalizationService LocalizationService
@inject ILanguageService LanguageService
@inject IPackageService PackageService
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@if (_code == null)
{
<p><em>@SharedLocalizer["Loading"]</em></p>
}
else
{
<TabStrip>
<TabPanel Name="Manage" ResourceKey="Manage" Heading="Manage">
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
<div class="col-sm-9">
<input id="code" class="form-control" @bind="@_code" readonly/>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
<div class="col-sm-9">
<select id="default" class="form-select" @bind="@_default" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
</form>
</TabPanel>
</TabStrip>
}
@code {
private ElementReference form;
private bool validated = false;
private int _languageId = -1;
private string _code = string.Empty;
private string _cultureName = string.Empty;
private string _default = "False";
private List<Language> _languages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
protected override async Task OnInitializedAsync()
{
_languageId = Int32.Parse(PageState.QueryString["id"]);
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
Language language = _languages.Where(x => x.LanguageId == _languageId).FirstOrDefault();
if (language != null)
{
_code = language.Code;
_cultureName = language.Name;
_default = language.IsDefault.ToString();
if (language.SiteId == null)
{
language.SiteId = PageState.Site.SiteId;
}
};
}
private async Task SaveLanguage()
{
Language language = _languages.Where(x => x.LanguageId == _languageId).FirstOrDefault();
if (language != null)
{
language.IsDefault = Boolean.Parse(_default);
try
{
await LanguageService.EditLanguageAsync(language);
if (language.IsDefault)
{
await SetCultureAsync(language.Code);
}
await logger.LogInformation("Language Edited {Language}", language);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Editing Language {Language} {Error}", language, ex.Message);
AddModuleMessage(Localizer["Error.Language.Edit"], MessageType.Error);
}
};
}
private async Task SetCultureAsync(string culture)
{
if (culture != CultureInfo.CurrentUICulture.Name)
{
var interop = new Interop(JSRuntime);
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360, true, "Lax");
}
}
}

View File

@ -14,8 +14,9 @@ else
{
<ActionLink Action="Add" Text="Add Language" ResourceKey="AddLanguage" />
<Pager Items="@_languages">
<Pager Items="@_languages" SearchProperties="Name,Code">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["Code"]</th>
@ -27,6 +28,12 @@ else
}
</Header>
<Row>
<td>
@if (!context.IsDefault)
{
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.LanguageId.ToString())" ResourceKey="EditLanguage" />
}
</td>
<td><ActionDialog Header="Delete Language" Message="@string.Format(Localizer["Confirm.Language.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@((context.IsDefault && _languages.Count > 2) || context.Code == Constants.DefaultCulture)" ResourceKey="DeleteLanguage" /></td>
<td>@context.Name</td>
<td>@context.Code</td>

View File

@ -8,63 +8,77 @@
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<AuthorizeView Roles="@RoleNames.Registered">
<Authorizing>
<text>...</text>
</Authorizing>
<NotAuthorized>
@if (!twofactor)
{
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="Oqtane-Modules-Admin-Login" @onkeypress="@(e => KeyPressed(e))">
@if (_allowexternallogin)
{
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
<br /><br />
}
@if (_allowsitelogin)
{
<div class="form-group">
<Label Class="control-label" For="username" HelpText="Please enter your Username" ResourceKey="Username">Username:</Label>
<input id="username" type="text" @ref="username" class="form-control" placeholder="@Localizer["Username.Placeholder"]" @bind="@_username" required />
</div>
<div class="form-group mt-2">
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
<div class="input-group">
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" required />
@if (PageState.User != null)
{
<ModuleMessage Message="@Localizer["Info.SignedIn"]" Type="MessageType.Info" />
}
else
{
@if (!twofactor)
{
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="Oqtane-Modules-Admin-Login" @onkeypress="@(e => KeyPressed(e))">
@if (_allowexternallogin)
{
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
<br />
<br />
}
@if (_allowsitelogin)
{
<div class="form-group">
<Label Class="control-label" For="username" HelpText="Please enter your Username" ResourceKey="Username">Username:</Label>
<input id="username" type="text" @ref="username" class="form-control" placeholder="@Localizer["Username.Placeholder"]" @bind="@_username" @bind:event="oninput" required />
</div>
<div class="form-group mt-2">
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
<div class="input-group">
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" @bind:event="oninput" required />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
<div class="form-group mt-2">
<div class="form-check">
<input id="remember" type="checkbox" class="form-check-input" @bind="@_remember" />
<Label Class="control-label" For="remember" HelpText="Specify if you would like to be signed back in automatically the next time you visit this site" ResourceKey="Remember">Remember Me?</Label>
</div>
</div>
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
<br /><br />
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
}
</div>
</form>
}
else
{
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container Oqtane-Modules-Admin-Login">
<div class="form-group">
<Label Class="control-label" For="code" HelpText="Please enter the secure verification code which was sent to you by email" ResourceKey="Code">Verification Code:</Label>
<input id="code" class="form-control" @bind="@_code" placeholder="@Localizer["Code.Placeholder"]" maxlength="6" required />
</div>
<br />
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Cancel"]</button>
</div>
</form>
}
</NotAuthorized>
</AuthorizeView>
</div>
</div>
<div class="form-group mt-2">
@if (!_alwaysremember)
{
<div class="form-check">
<input id="remember" type="checkbox" class="form-check-input" @bind="@_remember" />
<Label Class="control-label" For="remember" HelpText="Specify if you would like to be signed back in automatically the next time you visit this site" ResourceKey="Remember">Remember Me?</Label>
</div>
}
</div>
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
<br />
<br />
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
@if (PageState.Site.AllowRegistration)
{
<br />
<br />
<NavLink href="@NavigateUrl("register")">@Localizer["Register"]</NavLink>
}
}
</div>
</form>
}
else
{
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container Oqtane-Modules-Admin-Login">
<div class="form-group">
<Label Class="control-label" For="code" HelpText="Please enter the secure verification code which was sent to you by email" ResourceKey="Code">Verification Code:</Label>
<input id="code" class="form-control" @bind="@_code" placeholder="@Localizer["Code.Placeholder"]" maxlength="6" required />
</div>
<br />
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Cancel"]</button>
</div>
</form>
}
}
@code {
private bool _allowsitelogin = true;
@ -78,11 +92,11 @@
private string _passwordtype = "password";
private string _togglepassword = string.Empty;
private bool _remember = false;
private bool _alwaysremember = false;
private string _code = string.Empty;
private string _returnUrl = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
public override bool? Prerender => true;
public override List<Resource> Resources => new List<Resource>()
{
@ -93,20 +107,9 @@
{
try
{
if (PageState.QueryString.ContainsKey("returnurl"))
{
_returnUrl = PageState.QueryString["returnurl"];
}
_allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false;
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
if (_allowexternallogin && !_allowsitelogin)
{
// redirect to external login
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
return;
}
_alwaysremember = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AlwaysRemember", "false"));
_togglepassword = SharedLocalizer["ShowPassword"];
@ -170,11 +173,14 @@
{
if (firstRender && PageState.User == null && _allowsitelogin)
{
await username.FocusAsync();
if (!string.IsNullOrEmpty(username.Id)) // ensure username is visible in UI
{
await username.FocusAsync();
}
}
// redirect logged in user to specified page
if (PageState.User != null)
if (PageState.User != null && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
@ -192,7 +198,8 @@
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
if (!twofactor)
{
{
_remember = _alwaysremember || _remember;
user = await UserService.LoginUserAsync(user, hybrid, _remember);
}
else
@ -200,28 +207,31 @@
user = await UserService.VerifyTwoFactorAsync(user, _code);
}
if (user.IsAuthenticated)
if (user != null && user.IsAuthenticated)
{
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
await logger.LogInformation(LogFunction.Security, "Login Successful For {Username} From IP Address {IPAddress}", _username, SiteState.RemoteIPAddress);
// return url is not specified if user navigated directly to login page
var returnurl = (!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : PageState.Alias.Path;
if (hybrid)
{
// hybrid apps utilize an interactive login
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
NavigationManager.NavigateTo(NavigateUrl(returnurl, true));
}
else
{
// post back to the Login page so that the cookies are set correctly
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = WebUtility.UrlEncode(returnurl) };
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
await interop.SubmitForm(url, fields);
}
}
else
{
if (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "required" || user.TwoFactorRequired)
if (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "required" || (user != null && user.TwoFactorRequired))
{
twofactor = true;
validated = false;
@ -232,12 +242,12 @@
if (!twofactor)
{
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
}
else
{
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
}
}
}
@ -256,7 +266,7 @@
private void Cancel()
{
NavigationManager.NavigateTo(_returnUrl);
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
private async Task Forgot()
@ -324,7 +334,7 @@
private void ExternalLogin()
{
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + WebUtility.UrlEncode(PageState.ReturnUrl)), true);
}
}

View File

@ -63,7 +63,7 @@ else
<th>@Localizer["Function"]</th>
</Header>
<Row>
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Text="Details" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
<td class="@GetClass(context.Function)">@context.LogDate</td>
<td class="@GetClass(context.Function)">@context.Level</td>
<td class="@GetClass(context.Function)">@context.Feature</td>
@ -81,52 +81,53 @@ else
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of days of events to retain" ResourceKey="Retention">Retention (Days): </Label>
<div class="col-sm-9">
<input id="retention" class="form-control" @bind="@_retention" />
<input id="retention" type="number" min="0" step="1" class="form-control" @bind="@_retention" />
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
<ActionDialog Header="Clear Events" Message="Are You Sure You Wish To Remove All Log Events?" Action="DeleteLogs" Class="btn btn-danger" OnClick="@(async () => await DeleteLogs())" ResourceKey="DeleteLogs" />
</TabPanel>
</TabStrip>
}
@code {
private string _level = "-";
private string _function = "-";
private string _rows = "10";
private int _page = 1;
private List<Log> _logs;
private string _retention = "";
private string _level = "-";
private string _function = "-";
private string _rows = "10";
private int _page = 1;
private List<Log> _logs;
private int _retention = 30;
public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
try
{
if (UrlParameters.ContainsKey("level"))
{
_level = UrlParameters["level"];
}
if (UrlParameters.ContainsKey("function"))
{
_function = UrlParameters["function"];
}
if (UrlParameters.ContainsKey("rows"))
{
_rows = UrlParameters["rows"];
}
if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
{
_page = page;
}
protected override async Task OnParametersSetAsync()
{
try
{
if (UrlParameters.ContainsKey("level"))
{
_level = UrlParameters["level"];
}
if (UrlParameters.ContainsKey("function"))
{
_function = UrlParameters["function"];
}
if (UrlParameters.ContainsKey("rows"))
{
_rows = UrlParameters["rows"];
}
if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
{
_page = page;
}
await GetLogs();
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_retention = SettingService.GetSetting(settings, "LogRetention", "30");
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
}
catch (Exception ex)
{
@ -213,22 +214,37 @@ else
return classname;
}
private async Task SaveSiteSettings()
{
try
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "LogRetention", _retention, true);
private async Task SaveSiteSettings()
{
try
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
}
}
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
}
}
private async Task DeleteLogs()
{
try
{
await LogService.DeleteLogsAsync(PageState.Site.SiteId);
await GetLogs();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Logs {Error}", ex.Message);
AddModuleMessage(Localizer["Error.DeleteLogs"], MessageType.Error);
}
}
private void OnPageChange(int page)
{

View File

@ -66,6 +66,7 @@
<div class="container-fluid px-0">
<div class="row g-0 mb-2">
<div class="col-4">
<a href="@context.ProductUrl" target="_blank">
@if (context.LogoUrl != null)
{
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
@ -74,6 +75,7 @@
{
<img src="/package.png" class="img-fluid" alt="@context.Name" />
}
</a>
</div>
<div class="col-8 text-end">
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
@ -123,7 +125,7 @@
<TabPanel Name="Upload" ResourceKey="Upload" Heading="Upload">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
<Label Class="col-sm-3" HelpText="Upload one or more module packages." ResourceKey="Module">Module: </Label>
<div class="col-sm-9">
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
</div>

View File

@ -13,13 +13,13 @@
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
<Label Class="col-sm-3" For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or the word oqtane." ResourceKey="OwnerName">Owner Name: </Label>
<div class="col-sm-9">
<input id="owner" class="form-control" @bind="@_owner" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation." ResourceKey="ModuleName">Module Name: </Label>
<Label Class="col-sm-3" For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation or the word oqtane." ResourceKey="ModuleName">Module Name: </Label>
<div class="col-sm-9">
<input id="module" class="form-control" @bind="@_module" required />
</div>
@ -27,7 +27,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
<div class="col-sm-9">
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000" required></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
@ -111,6 +111,8 @@
private async Task CreateModule()
{
validated = true;
_owner = _owner.Trim();
_module = _module.Trim();
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
@ -118,6 +120,7 @@
{
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
{
if (string.IsNullOrEmpty(_description)) _description = _module;
if (IsValidXML(_description))
{
var template = _templates.FirstOrDefault(item => item.Name == _template);
@ -156,7 +159,7 @@
private bool IsValidXML(string description)
{
// must contain letters, digits, or spaces
return Regex.IsMatch(description, "^[A-Za-z0-9 ]+$");
return Regex.IsMatch(description, "^[A-Za-z0-9 .,!?]+$");
}
private void TemplateChanged(ChangeEventArgs e)

View File

@ -1,13 +1,15 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@inject ILanguageService LanguageService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@inject IPageModuleService PageModuleService
@inject IModuleService ModuleService
@inject IPageService PageService
@if (_initialized)
{
@ -30,7 +32,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
<div class="col-sm-9">
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -61,24 +63,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification." ResourceKey="PackageName">Package Name: </Label>
<div class="col-sm-9">
@if (!string.IsNullOrEmpty(_packagename))
{
<div class="input-group">
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
@if (string.IsNullOrEmpty(_packageurl))
{
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
}
else
{
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
}
</div>
}
else
{
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
}
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -131,10 +116,22 @@
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
</TabPanel>
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
<Pager Items="@_pagesWithModules" RowClass="align-middle">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
</Header>
<Row>
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
<td>@(string.IsNullOrEmpty(context.Title) ? @context.Name : @context.Title )</td>
</Row>
</Pager>
</TabPanel>
<TabPanel Name="Translations" ResourceKey="Translations" Heading="Translations">
@if (_languages != null && _languages.Count > 0)
{
<Pager Items="@_languages">
<Pager Items="@_languages">
<Header>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["Code"]</th>
@ -230,7 +227,6 @@
private string _moduledefinitionname = "";
private string _version;
private string _packagename = "";
private string _packageurl = "";
private string _owner = "";
private string _url = "";
private string _contact = "";
@ -240,6 +236,7 @@
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private List<Page> _pagesWithModules;
#pragma warning disable 649
private PermissionGrid _permissionGrid;
@ -291,6 +288,19 @@
_languages = _languages.OrderBy(item => item.Name).ToList();
}
// get distinct pages where module exists
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
var distinctPageIds = modules
.Where(md => md.ModuleDefinition?.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
.Select(md => md.PageId)
.Distinct();
// retrieve the pages which contain the module
var pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
_pagesWithModules = pages
.Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false)
.ToList();
_initialized = true;
}
}
@ -417,27 +427,5 @@
}
}
private async Task ValidatePackage()
{
try
{
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
{
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
}
else
{
_packageurl = package.PackageUrl;
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
}
}
private string Browse(Page page) => string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
}

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleService ModuleService
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@inject IStringLocalizer<Index> Localizer
@ -50,7 +51,7 @@ else
<th style="width: 1px;">&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
<td>
@if (context.AssemblyName != Constants.ClientId)
{
@ -70,7 +71,7 @@ else
}
</td>
<td>
@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
@if (context.AssemblyName == Constants.ClientId || _modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
{
<span>@SharedLocalizer["Yes"]</span>
}
@ -99,6 +100,7 @@ else
}
@code {
private List<Module> _modules;
private List<ModuleDefinition> _allModuleDefinitions;
private List<ModuleDefinition> _moduleDefinitions;
private List<Package> _packages;
@ -111,6 +113,7 @@ else
{
try
{
_modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
await LoadModuleDefinitions();

View File

@ -15,7 +15,7 @@
</div>
<button type="button" class="btn btn-success" @onclick="ExportModule">@Localizer["Export"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
@code {
private string _content = string.Empty;

View File

@ -17,7 +17,7 @@
</div>
<button type="button" class="btn btn-success" @onclick="ImportModule">@Localizer["Import"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
</form>
@code {

View File

@ -3,115 +3,145 @@
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@inject IPageService PageService
@inject IModuleService ModuleService
@inject IPageModuleService PageModuleService
@inject IStringLocalizer<Settings> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<TabStrip>
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
@if (_containers != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="module" HelpText="The name of the module" ResourceKey="Module">Module: </Label>
<div class="col-sm-9">
<input id="module" type="text" class="form-control" @bind="@_module" disabled />
@if (_initialized)
{
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<TabStrip ActiveTab="@_activetab">
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
@if (_containers != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="module" HelpText="The name of the module" ResourceKey="Module">Module: </Label>
<div class="col-sm-9">
<input id="module" type="text" class="form-control" @bind="@_module" disabled />
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="title" HelpText="Enter the title of the module" ResourceKey="Title">Title: </Label>
<div class="col-sm-9">
<input id="title" type="text" class="form-control" @bind="@_title" required />
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="title" HelpText="Enter the title of the module" ResourceKey="Title">Title: </Label>
<div class="col-sm-9">
<input id="title" type="text" class="form-control" @bind="@_title" required />
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="container" HelpText="Select the module's container" ResourceKey="Container">Container: </Label>
<div class="col-sm-9">
<select id="container" class="form-select" @bind="@_containerType" required>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="allpages" HelpText="Indicate if this module should be displayed on all pages" ResourceKey="DisplayOnAllPages">Display On All Pages? </Label>
<div class="col-sm-9">
<select id="allpages" class="form-select" @bind="@_allPages" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
<div class="col-sm-9">
<select id="page" class="form-select" @bind="@_pageId" required>
@if (PageState.Page.UserId != null)
{
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
}
else
{
foreach (Page p in PageState.Pages)
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="pane" HelpText="The pane where the module will be displayed" ResourceKey="Pane">Pane: </Label>
<div class="col-sm-9">
<select class="form-select" @bind="@_pane">
@foreach (string pane in PageState.Page.Panes)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
<option value="@pane">@pane Pane</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="container" HelpText="Select the module's container" ResourceKey="Container">Container: </Label>
<div class="col-sm-9">
<select id="container" class="form-select" @bind="@_containerType" required>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this module is active" ResourceKey="EffectiveDate">Effective Date: </Label>
<div class="col-sm-9">
<input type="date" id="effectiveDate" class="form-control" @bind="@_effectivedate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this module expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
<div class="col-sm-9">
<input type="date" id="expiryDate" class="form-control" @bind="@_expirydate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="allpages" HelpText="Indicate if this module should be displayed on all pages" ResourceKey="DisplayOnAllPages">Display On All Pages? </Label>
<div class="col-sm-9">
<select id="allpages" class="form-select" @bind="@_allPages" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
<div class="col-sm-9">
<select id="page" class="form-select" @bind="@_pageId" required>
@if (PageState.Page.UserId != null)
{
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
}
else
{
if (_pages != null)
{
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
foreach (Page p in _pages)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
{
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
}
}
}
}
}
</select>
</select>
</div>
</div>
</div>
</div>
}
</TabPanel>
<TabPanel Name="Permissions" ResourceKey="Permissions">
@if (_permissions != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" PermissionList="@_permissions" @ref="_permissionGrid" />
}
</TabPanel>
<TabPanel Name="Permissions" Heading="Permissions" ResourceKey="Permissions">
@if (_permissions != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" PermissionList="@_permissions" @ref="_permissionGrid" />
</div>
</div>
</div>
}
</TabPanel>
@if (_moduleSettingsType != null)
{
<TabPanel Name="ModuleSettings" Heading="@_moduleSettingsTitle" ResourceKey="ModuleSettings">
@ModuleSettingsComponent
</TabPanel>
}
</TabPanel>
@if (_moduleSettingsType != null)
{
<TabPanel Name="ModuleSettings" Heading="@_moduleSettingsTitle" ResourceKey="ModuleSettings">
@ModuleSettingsComponent
</TabPanel>
}
@if (_containerSettingsType != null)
{
<TabPanel Name="ContainerSettings" Heading="Container Settings" ResourceKey="ContainerSettings">
@ContainerSettingsComponent
</TabPanel>
}
</TabStrip>
<br />
<button type="button" class="btn btn-success" @onclick="SaveModule">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
</form>
@if (_containerSettingsType != null)
{
<TabPanel Name="ContainerSettings" Heading="Container Settings" ResourceKey="ContainerSettings">
@ContainerSettingsComponent
</TabPanel>
}
</TabStrip>
<br />
<button type="button" class="btn btn-success" @onclick="SaveModule">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
</form>
}
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override string Title => "Module Settings";
private bool _initialized = false;
private ElementReference form;
private bool validated = false;
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _module;
private string _title;
private string _pane;
private string _containerType;
private string _allPages = "false";
private string _permissionNames = "";
@ -120,7 +150,7 @@
private PermissionGrid _permissionGrid;
private Type _moduleSettingsType;
private object _moduleSettings;
private string _moduleSettingsTitle = "Module Settings";
private string _moduleSettingsTitle;
private RenderFragment ModuleSettingsComponent { get; set; }
private Type _containerSettingsType;
private object _containerSettings;
@ -129,100 +159,125 @@
private DateTime createdon;
private string modifiedby;
private DateTime modifiedon;
private DateTime? _effectivedate = null;
private DateTime? _expirydate = null;
private List<Page> _pages;
private string _activetab = "";
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
_module = ModuleState.ModuleDefinition.Name;
SetModuleTitle(Localizer["ModuleSettings.Title"]);
_title = ModuleState.Title;
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
_pane = ModuleState.Pane;
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
_containerType = ModuleState.ContainerType;
_allPages = ModuleState.AllPages.ToString();
_permissions = ModuleState.PermissionList;
_pageId = ModuleState.PageId.ToString();
createdby = ModuleState.CreatedBy;
createdon = ModuleState.CreatedOn;
modifiedby = ModuleState.ModifiedBy;
modifiedon = ModuleState.ModifiedOn;
_containerType = ModuleState.ContainerType;
_allPages = ModuleState.AllPages.ToString();
_permissions = ModuleState.PermissionList;
_pageId = ModuleState.PageId.ToString();
createdby = ModuleState.CreatedBy;
createdon = ModuleState.CreatedOn;
modifiedby = ModuleState.ModifiedBy;
modifiedon = ModuleState.ModifiedOn;
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (ModuleState.ModuleDefinition != null)
{
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
if (ModuleState.ModuleDefinition != null)
{
_module = ModuleState.ModuleDefinition.Name;
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
{
// module settings type explicitly declared in IModule interface
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
}
else
{
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
}
if (_moduleSettingsType != null)
{
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
if (!string.IsNullOrEmpty(moduleobject.Title))
{
_moduleSettingsTitle = moduleobject.Title;
}
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
{
// module settings type explicitly declared in IModule interface
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
}
else
{
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
}
if (_moduleSettingsType != null)
{
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
if (!string.IsNullOrEmpty(moduleobject.Title))
{
_moduleSettingsTitle = moduleobject.Title;
}
ModuleSettingsComponent = builder =>
{
builder.OpenComponent(0, _moduleSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
builder.CloseComponent();
};
}
}
else
{
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
}
ModuleSettingsComponent = builder =>
{
builder.OpenComponent(0, _moduleSettingsType);
builder.AddAttribute(1, "RenderModeBoundary", RenderModeBoundary);
builder.AddComponentReferenceCapture(2, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
builder.CloseComponent();
};
}
}
else
{
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
}
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
{
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
if (_containerSettingsType != null)
{
ContainerSettingsComponent = builder =>
{
builder.OpenComponent(0, _containerSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
builder.CloseComponent();
};
}
}
}
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
{
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
if (_containerSettingsType != null)
{
ContainerSettingsComponent = builder =>
{
builder.OpenComponent(0, _containerSettingsType);
builder.AddAttribute(1, "RenderModeBoundary", RenderModeBoundary);
builder.AddComponentReferenceCapture(2, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
builder.CloseComponent();
};
}
}
private async Task SaveModule()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
if (!string.IsNullOrEmpty(_title))
{
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
pagemodule.PageId = int.Parse(_pageId);
pagemodule.Title = _title;
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
_initialized = true;
}
var module = ModuleState;
module.AllPages = bool.Parse(_allPages);
module.PageModuleId = ModuleState.PageModuleId;
module.PermissionList = _permissionGrid.GetPermissionList();
await ModuleService.UpdateModuleAsync(module);
private async Task SaveModule()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
if (!string.IsNullOrEmpty(_title))
{
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
{
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
return;
}
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
pagemodule.PageId = int.Parse(_pageId);
pagemodule.Title = _title;
pagemodule.Pane = _pane;
pagemodule.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate);
pagemodule.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
var module = ModuleState;
module.AllPages = bool.Parse(_allPages);
module.PageModuleId = ModuleState.PageModuleId;
module.PermissionList = _permissionGrid.GetPermissionList();
await ModuleService.UpdateModuleAsync(module);
if (_moduleSettingsType != null)
{
@ -243,17 +298,18 @@
await containerSettingsControl.UpdateSettings();
}
NavigationManager.NavigateTo(NavigateUrl());
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
else
{
_activetab = "Settings";
AddModuleMessage(Localizer["Message.Required.Title"], MessageType.Warning);
}
}
else
{
_activetab = "Settings";
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
}
}
}

View File

@ -16,7 +16,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_name" required />
<input id="name" class="form-control" @bind="@_name" maxlength="50" required />
</div>
</div>
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
@ -26,7 +26,7 @@
<div class="col-sm-9">
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
<option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option>
@foreach (Page page in PageState.Pages)
@foreach (Page page in _pages)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
{
@ -101,13 +101,13 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
<div class="col-sm-9">
<input id="path" class="form-control" @bind="@_path" />
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it" ResourceKey="Redirect">Redirect: </Label>
<div class="col-sm-9">
<input id="url" class="form-control" @bind="@_url" />
<input id="url" class="form-control" @bind="@_url" maxlength="500" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -119,6 +119,18 @@
<i class="@_icon"></i>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this page is active" ResourceKey="EffectiveDate">Effective Date: </Label>
<div class="col-sm-9">
<input type="date" id="effectiveDate" class="form-control" @bind="@_effectivedate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this page expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
<div class="col-sm-9">
<input type="date" id="expiryDate" class="form-control" @bind="@_expirydate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
<div class="col-sm-9">
@ -135,7 +147,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
<div class="col-sm-9">
<input id="title" class="form-control" @bind="@_title" />
<input id="title" class="form-control" @bind="@_title" maxlength="200" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -144,7 +156,14 @@
<select id="theme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
@if (theme.TypeName == PageState.Site.DefaultThemeType)
{
<option value="@theme.TypeName">*@theme.Name*</option>
}
else
{
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</div>
@ -167,13 +186,13 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
<div class="col-sm-9">
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3" maxlength="4000"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
<div class="col-sm-9">
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3" maxlength="4000"></textarea>
</div>
</div>
</div>
@ -186,12 +205,6 @@
</div>
</div>
</TabPanel>
@if (_themeSettingsType != null)
{
<TabPanel Name="ThemeSettings" Heading=@Localizer["Theme.Heading"] ResourceKey="ThemeSettings">
@ThemeSettingsComponent
</TabPanel>
}
</TabStrip>
<br />
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
@ -207,6 +220,7 @@
private bool validated = false;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pages;
private int _pageId;
private string _name;
private string _parentid = "-1";
@ -226,18 +240,19 @@
private string _bodycontent;
private string _permissions = null;
private PermissionGrid _permissionGrid;
private Type _themeSettingsType;
private object _themeSettings;
private RenderFragment ThemeSettingsComponent { get; set; }
private bool _refresh = false;
protected Page _parent = null;
protected Dictionary<string, string> _icons;
private string _iconresources = "";
private DateTime? _effectivedate = null;
private DateTime? _expirydate = null;
protected override async Task OnInitializedAsync()
{
try
{
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (PageState.QueryString.ContainsKey("id"))
{
_pageId = Int32.Parse(PageState.QueryString["id"]);
@ -258,14 +273,15 @@
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = PageState.Site.DefaultContainerType;
_children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
_children.Add(p);
}
}
ThemeSettings();
_effectivedate = Utilities.UtcAsLocalDate(PageState.Page.EffectiveDate);
_expirydate = Utilities.UtcAsLocalDate(PageState.Page.ExpiryDate);
_initialized = true;
}
else
@ -274,20 +290,20 @@
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Page {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Page {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
}
}
private async void ParentChanged(ChangeEventArgs e)
{
try
{
_parentid = (string)e.Value;
private async void ParentChanged(ChangeEventArgs e)
{
try
{
_parentid = (string)e.Value;
_children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
@ -295,152 +311,151 @@
}
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
}
}
private void ThemeChanged(ChangeEventArgs e)
{
_themetype = (string)e.Value;
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
}
catch (Exception ex)
{
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = _containers.First().TypeName;
ThemeSettings();
StateHasChanged();
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
await ScrollToPageTop();
}
}
private void ThemeSettings()
{
_themeSettingsType = null;
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
{
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
if (_themeSettingsType != null)
{
ThemeSettingsComponent = builder =>
{
builder.OpenComponent(0, _themeSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
builder.CloseComponent();
};
}
_refresh = true;
}
}
private async Task ThemeChanged(ChangeEventArgs e)
{
_themetype = (string)e.Value;
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = _containers.First().TypeName;
StateHasChanged();
private async Task SavePage()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
Page page = null;
try
{
// if theme chosen is different than default site theme, display warning message to user
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
{
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
await ScrollToPageTop();
}
}
private async Task SavePage()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
Page page = null;
try
{
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
{
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
await ScrollToPageTop();
return;
}
if (!string.IsNullOrEmpty(_themetype) && !string.IsNullOrEmpty(_containertype))
{
page = new Page();
page.SiteId = PageState.Page.SiteId;
page.Name = _name;
{
page = new Page();
page.SiteId = PageState.Page.SiteId;
page.Name = _name;
if (string.IsNullOrEmpty(_path))
{
_path = _name;
}
if (_path.Contains("/"))
{
if (_path.EndsWith("/") && _path != "/")
{
_path = _path.Substring(0, _path.Length - 1);
}
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (_parentid == "-1")
{
page.ParentId = null;
}
else
{
page.ParentId = Int32.Parse(_parentid);
}
if (string.IsNullOrEmpty(_path))
{
_path = _name;
}
if (_parentid == "-1")
{
page.ParentId = null;
page.Path = Utilities.GetFriendlyUrl(_path);
}
else
{
page.ParentId = Int32.Parse(_parentid);
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
if (_path.Contains("/"))
{
if (_path.EndsWith("/") && _path != "/")
{
_path = _path.Substring(0, _path.Length - 1);
}
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (_parentid == "-1")
{
page.Path = Utilities.GetFriendlyUrl(_path);
}
else
{
Page parent = _pages.FirstOrDefault(item => item.PageId == page.ParentId);
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (_pages.Any(item => item.Path == page.Path))
{
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
return;
}
if (_pages.Any(item => item.Path == page.Path))
{
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
await ScrollToPageTop();
return;
}
if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower()))
{
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning);
return;
}
if (page.ParentId == null && Constants.ReservedRoutes.Contains(page.Name.ToLower()))
{
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], page.Name), MessageType.Warning);
await ScrollToPageTop();
return;
}
Page child;
switch (_insert)
{
case "<<":
page.Order = 0;
break;
case "<":
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
}
Page child;
switch (_insert)
{
case "<<":
page.Order = 0;
break;
case "<":
child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order - 1;
break;
case ">":
child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order + 1;
break;
case ">>":
page.Order = int.MaxValue;
break;
}
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
page.Url = _url;
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
page.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate);
page.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
page.UserId = null;
// appearance
page.Title = _title;
page.Icon = (_icon == null ? string.Empty : _icon);
page.ThemeType = _themetype;
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = string.Empty;
}
page.DefaultContainerType = _containertype;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
page.DefaultContainerType = string.Empty;
}
page.ThemeType = _themetype;
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
{
page.ThemeType = string.Empty;
}
page.DefaultContainerType = _containertype;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
page.DefaultContainerType = string.Empty;
}
// page content
page.HeadContent = _headcontent;
page.BodyContent = _bodycontent;
// permissions
page.PermissionList = _permissionGrid.GetPermissionList();
page.PermissionList = _permissionGrid.GetPermissionList();
page = await PageService.AddPageAsync(page);
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
@ -448,7 +463,7 @@
await logger.LogInformation("Page Added {Page}", page);
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
{
NavigationManager.NavigateTo(page.Path); // redirect to new page
NavigationManager.NavigateTo(NavigateUrl(page.Path), true); // redirect to page added and reload
}
else
{
@ -458,6 +473,7 @@
else
{
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
await ScrollToPageTop();
}
}
@ -465,11 +481,13 @@
{
await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
await ScrollToPageTop();
}
}
else
{
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
await ScrollToPageTop();
}
}

View File

@ -1,10 +1,12 @@
@namespace Oqtane.Modules.Admin.Pages
@using Oqtane.Interfaces
@using System.Globalization
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@inject IPageModuleService PageModuleService
@inject IThemeService ThemeService
@inject IModuleService ModuleService
@inject IThemeService ThemeService
@inject ISystemService SystemService
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -30,7 +32,7 @@
<div class="col-sm-9">
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
<option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option>
@foreach (Page page in PageState.Pages)
@foreach (Page page in _pages)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
{
@ -114,7 +116,7 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. Please note that spaces and punctuation will be replaced by a dash. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
<div class="col-sm-9">
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
</div>
@ -134,6 +136,18 @@
<i class="@_icon"></i>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this page is active" ResourceKey="EffectiveDate">Effective Date: </Label>
<div class="col-sm-9">
<input type="date" id="effectiveDate" class="form-control" @bind="@_effectivedate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this page expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
<div class="col-sm-9">
<input type="date" id="expiryDate" class="form-control" @bind="@_expirydate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
<div class="col-sm-9">
@ -158,7 +172,14 @@
<select id="theme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
@if (theme.TypeName == PageState.Site.DefaultThemeType)
{
<option value="@theme.TypeName">*@theme.Name*</option>
}
else
{
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</div>
@ -167,9 +188,12 @@
<Label Class="col-sm-3" For="container" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
<div class="col-sm-9">
<select id="container" class="form-select" @bind="@_containertype" required>
@foreach (var container in _containers)
@if (_containers != null)
{
<option value="@container.TypeName">@container.Name</option>
foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
}
</select>
</div>
@ -181,13 +205,13 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
<div class="col-sm-9">
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3" maxlength="4000"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="bodycontent" HelpText="Optionally enter content to be included in the page body (ie. script tags)" ResourceKey="BodyContent">Body Content: </Label>
<div class="col-sm-9">
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3"></textarea>
<textarea id="bodycontent" class="form-control" @bind="@_bodycontent" rows="3" maxlength="4000"></textarea>
</div>
</div>
</div>
@ -222,7 +246,7 @@
@if (_themeSettingsType != null)
{
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
@ThemeSettingsComponent
@_themeSettingsComponent
</TabPanel>
<br />
}
@ -239,13 +263,26 @@
<input id="title" class="form-control" @bind="@_title" maxlength="200" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="path" HelpText="Provide a url path for your personalized page. Please note that spaces and punctuation will be replaced by a dash." ResourceKey="PersonalizedUrlPath">Url Path: </Label>
<div class="col-sm-9">
<input id="path" class="form-control" @bind="@_path" maxlength="256" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
<div class="col-sm-9">
<select id="theme" class="form-select" @bind="@_themetype" required>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
@if (theme.TypeName == PageState.Site.DefaultThemeType)
{
<option value="@theme.TypeName">*@theme.Name*</option>
}
else
{
<option value="@theme.TypeName">@theme.Name</option>
}
}
</select>
</div>
@ -266,7 +303,7 @@
@if (_themeSettingsType != null)
{
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
@ThemeSettingsComponent
@_themeSettingsComponent
</TabPanel>
<br />
}
@ -286,6 +323,7 @@
private bool validated = false;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pages;
private int _pageId;
private string _name;
private string _currentparentid;
@ -305,7 +343,7 @@
private string _containertype = "-";
private Type _themeSettingsType;
private object _themeSettings;
private RenderFragment ThemeSettingsComponent { get; set; }
private RenderFragment _themeSettingsComponent { get; set; }
private string _headcontent;
private string _bodycontent;
private List<Permission> _permissions = null;
@ -322,11 +360,14 @@
protected Page _parent = null;
protected Dictionary<string, string> _icons;
private string _iconresources = "";
private DateTime? _effectivedate = null;
private DateTime? _expirydate = null;
protected override async Task OnInitializedAsync()
{
try
{
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
_pageId = Int32.Parse(PageState.QueryString["id"]);
_page = await PageService.GetPageAsync(_pageId);
_icons = await SystemService.GetIconsAsync();
@ -342,10 +383,10 @@
else
{
_parentid = _page.ParentId.ToString();
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
_parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
}
_children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
{
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
@ -370,11 +411,17 @@
}
_url = _page.Url;
_icon = _page.Icon;
_effectivedate = Utilities.UtcAsLocalDate(_page.EffectiveDate);
_expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate);
_ispersonalizable = _page.IsPersonalizable.ToString();
// appearance
_title = _page.Title;
_themetype = _page.ThemeType;
if (string.IsNullOrEmpty(_themetype))
{
_themetype = PageState.Site.DefaultThemeType;
}
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = _page.DefaultContainerType;
@ -391,7 +438,8 @@
_permissions = _page.PermissionList;
// page modules
_pageModules = PageState.Modules.Where(m => m.PageId == _page.PageId).ToList();
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
_pageModules = modules.Where(item => item.PageId == _page.PageId && !item.IsDeleted).ToList();
// audit
_createdby = _page.CreatedBy;
@ -423,7 +471,7 @@
{
_parentid = (string)e.Value;
_children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
@ -437,35 +485,42 @@
{
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
await ScrollToPageTop();
}
}
private void ThemeChanged(ChangeEventArgs e)
private async Task ThemeChanged(ChangeEventArgs e)
{
_themetype = (string)e.Value;
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = _containers.First().TypeName;
ThemeSettings();
StateHasChanged();
// if theme chosen is different than default site theme, display warning message to user
if (ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
{
AddModuleMessage(Localizer["ThemeChanged.Message"], MessageType.Warning);
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = _containers.First().TypeName;
ThemeSettings();
StateHasChanged();
await ScrollToPageTop();
}
}
private void ThemeSettings()
{
_themeSettingsType = null;
_themeSettingsComponent = null;
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
{
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
if (_themeSettingsType != null)
{
ThemeSettingsComponent = builder =>
_themeSettingsComponent = builder =>
{
builder.OpenComponent(0, _themeSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
builder.AddAttribute(1, "RenderModeBoundary", RenderModeBoundary);
builder.AddComponentReferenceCapture(2, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
builder.CloseComponent();
};
}
@ -481,16 +536,32 @@
{
try
{
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
{
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
await ScrollToPageTop();
return;
}
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
{
string currentPath = _page.Path;
_page.Name = _name;
if (_parentid == "-1")
{
_page.ParentId = null;
}
else
{
_page.ParentId = Int32.Parse(_parentid);
}
if (string.IsNullOrEmpty(_path))
{
_path = _name;
}
if (_path.Contains("/"))
{
if (_path.EndsWith("/") && _path != "/")
@ -499,16 +570,13 @@
}
_path = _path.Substring(_path.LastIndexOf("/") + 1);
}
if (_parentid == "-1")
{
_page.ParentId = null;
_page.Path = Utilities.GetFriendlyUrl(_path);
}
else
{
_page.ParentId = Int32.Parse(_parentid);
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
Page parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
if (parent.Path == string.Empty)
{
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
@ -519,16 +587,17 @@
}
}
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
{
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
await ScrollToPageTop();
return;
}
if (_page.ParentId == null && Constants.ReservedRoutes.Contains(_page.Name.ToLower()))
{
AddModuleMessage(string.Format(Localizer["Message.Page.Reserved"], _page.Name), MessageType.Warning);
await ScrollToPageTop();
return;
}
@ -541,11 +610,11 @@
_page.Order = 0;
break;
case "<":
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
child = _pages.FirstOrDefault(item => item.PageId == _childid);
if (child != null) _page.Order = child.Order - 1;
break;
case ">":
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
child = _pages.FirstOrDefault(item => item.PageId == _childid);
if (child != null) _page.Order = child.Order + 1;
break;
case ">>":
@ -557,6 +626,8 @@
_page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
_page.Url = _url;
_page.Icon = _icon ?? string.Empty;
_page.EffectiveDate = Utilities.LocalDateAndTimeAsUtc(_effectivedate);
_page.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
_page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
// appearance
@ -601,27 +672,30 @@
await logger.LogInformation("Page Saved {Page}", _page);
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
{
NavigationManager.NavigateTo(PageState.ReturnUrl);
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
}
else
{
NavigationManager.NavigateTo(NavigateUrl());
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
}
}
else
{
AddModuleMessage(Localizer["Message.Required.PageInfo"], MessageType.Warning);
await ScrollToPageTop();
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Page {Page} {Error}", _page, ex.Message);
AddModuleMessage(Localizer["Error.Page.Save"], MessageType.Error);
await ScrollToPageTop();
}
}
else
{
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
await ScrollToPageTop();
}
}

View File

@ -5,11 +5,11 @@
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
@if (_pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)">
<Pager Items="@_pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
@ -17,7 +17,7 @@
<th>@SharedLocalizer["Name"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
@ -28,6 +28,21 @@
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private List<Page> _pages;
protected override async Task OnInitializedAsync()
{
try
{
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pages {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
}
}
private async Task DeletePage(Page page)
{
try

View File

@ -22,7 +22,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="The help text displayed to the user for this profile item" ResourceKey="Description">Description: </Label>
<div class="col-sm-9">
<textarea id="description" class="form-control" @bind="@_description" rows="5" maxlength="256" required ></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="256" required></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
@ -34,19 +34,25 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="order" HelpText="The index order of where this profile item should be displayed" ResourceKey="Order">Order: </Label>
<div class="col-sm-9">
<input id="order" class="form-control" @bind="@_vieworder" maxlength="4" required />
<input id="order" class="form-control" @bind="@_vieworder" min="0" max="9999" type="number" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="length" HelpText="The max number of characters this profile item should accept (enter zero for unlimited)" ResourceKey="Length">Length: </Label>
<div class="col-sm-9">
<input id="length" class="form-control" @bind="@_maxlength" maxlength="4" required />
<input id="length" class="form-control" @bind="@_maxlength" min="0" max="524288" type="number" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="rows" HelpText="The number of rows for text entry (one is the default)" ResourceKey="Rows">Rows: </Label>
<div class="col-sm-9">
<input id="rows" class="form-control" @bind="@_rows" min="1" max="10" type="number" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultVal" HelpText="The default value for this profile item" ResourceKey="DefaultValue">Default Value: </Label>
<div class="col-sm-9">
<input id="defaultVal" class="form-control" @bind="@_defaultvalue" maxlength="2000"/>
<input id="defaultVal" class="form-control" @bind="@_defaultvalue" maxlength="2000" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -70,6 +76,12 @@
<input id="validation" class="form-control" @bind="@_validation" maxlength="200" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="autocomplete" HelpText="The HTML autocomplete attribute allows you to specify browser behavior for automated user assistance in filling out form field values. Allowable values are blank (default), 'on', 'off', or any value from the standardized taxonomy defined for this attribute." ResourceKey="Autocomplete">Autocomplete: </Label>
<div class="col-sm-9">
<input id="autocomplete" class="form-control" @bind="@_autocomplete" maxlength="30" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="private" HelpText="Should this profile item be visible to all users?" ResourceKey="Private">Private? </Label>
<div class="col-sm-9">
@ -83,7 +95,7 @@
<br />
<button type="button" class="btn btn-success" @onclick="SaveProfile">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
@if (PageState.QueryString.ContainsKey("id"))
@if (PageState.QueryString.ContainsKey("id"))
{
<br />
<br />
@ -101,9 +113,11 @@
private string _category = string.Empty;
private string _vieworder = "0";
private string _maxlength = "0";
private string _rows = "1";
private string _defaultvalue = string.Empty;
private string _options = string.Empty;
private string _validation = string.Empty;
private string _autocomplete = string.Empty;
private string _isrequired = "False";
private string _isprivate = "False";
private string createdby;
@ -131,9 +145,11 @@
_category = profile.Category;
_vieworder = profile.ViewOrder.ToString();
_maxlength = profile.MaxLength.ToString();
_rows = profile.Rows.ToString();
_defaultvalue = profile.DefaultValue;
_options = profile.Options;
_validation = profile.Validation;
_autocomplete = profile.Autocomplete;
_isrequired = profile.IsRequired.ToString();
_isprivate = profile.IsPrivate.ToString();
createdby = profile.CreatedBy;
@ -175,11 +191,14 @@
profile.Category = _category;
profile.ViewOrder = int.Parse(_vieworder);
profile.MaxLength = int.Parse(_maxlength);
profile.Rows = int.Parse(_rows);
profile.DefaultValue = _defaultvalue;
profile.Options = _options;
profile.Validation = _validation;
profile.Autocomplete = _autocomplete;
profile.IsRequired = (_isrequired == null ? false : Boolean.Parse(_isrequired));
profile.IsPrivate = (_isprivate == null ? false : Boolean.Parse(_isprivate));
if (_profileid != -1)
{
profile = await ProfileService.UpdateProfileAsync(profile);

View File

@ -12,7 +12,7 @@ else
{
<ActionLink Action="Add" Text="Add Profile" Security="SecurityAccessLevel.Edit" ResourceKey="AddProfile" />
<Pager Items="@_profiles">
<Pager Items="@_profiles" SearchProperties="Title,Category">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
@ -22,7 +22,7 @@ else
<th>@Localizer["Order"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
<td>@context.Name</td>
<td>@context.Title</td>

View File

@ -13,71 +13,71 @@
}
else
{
<TabStrip>
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
@if (!_pages.Where(item => item.IsDeleted).Any())
{
<br />
<p>@Localizer["NoPage.Deleted"]</p>
}
else
{
<Pager Items="@_pages.Where(item => item.IsDeleted)" CurrentPage="@_pagePage.ToString()" OnPageChange="OnPageChangePage">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
<th>@Localizer["DeletedBy"]</th>
<th>@Localizer["DeletedOn"]</th>
</Header>
<Row>
<TabStrip>
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
@if (!_pages.Where(item => item.IsDeleted).Any())
{
<br />
<p>@Localizer["NoPage.Deleted"]</p>
}
else
{
<Pager Items="@_pages.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pagePage.ToString()" OnPageChange="OnPageChangePage">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Path"]</th>
<th>@Localizer["DeletedBy"]</th>
<th>@Localizer["DeletedOn"]</th>
</Header>
<Row>
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
<td>@context.Name</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
</Row>
</Pager>
<br />
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
}
</TabPanel>
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
@if (!_modules.Where(item => item.IsDeleted).Any())
{
<br />
<p>@Localizer["NoModule.Deleted"]</p>
}
else
{
<Pager Items="@_modules.Where(item => item.IsDeleted)" CurrentPage="@_pageModule.ToString()" OnPageChange="OnPageChangeModule">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["Page"]</th>
<th>@Localizer["Module"]</th>
<th>@Localizer["DeletedBy"]</th>
<th>@Localizer["DeletedOn"]</th>
</Header>
<Row>
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
<td>@_pages.Find(item => item.PageId == context.PageId).Name</td>
<td>@context.Title</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
</Row>
</Pager>
<br />
<ActionDialog Header="Remove All Deleted Modules" Message="Are You Sure You Wish To Permanently Remove All Deleted Modules?" Action="Remove All Deleted Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
}
</TabPanel>
</TabStrip>
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
<td>@context.Path</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
</Row>
</Pager>
<br />
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
}
</TabPanel>
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
@if (!_modules.Where(item => item.IsDeleted).Any())
{
<br />
<p>@Localizer["NoModule.Deleted"]</p>
}
else
{
<Pager Items="@_modules.Where(item => item.IsDeleted).OrderByDescending(item => item.DeletedOn)" CurrentPage="@_pageModule.ToString()" OnPageChange="OnPageChangeModule">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["Page"]</th>
<th>@Localizer["Module"]</th>
<th>@Localizer["DeletedBy"]</th>
<th>@Localizer["DeletedOn"]</th>
</Header>
<Row>
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
<td>@_pages.Find(item => item.PageId == context.PageId).Name</td>
<td>@context.Title</td>
<td>@context.DeletedBy</td>
<td>@context.DeletedOn</td>
</Row>
</Pager>
<br />
<ActionDialog Header="Remove All Deleted Modules" Message="Are You Sure You Wish To Permanently Remove All Deleted Modules?" Action="Remove All Deleted Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
}
</TabPanel>
</TabStrip>
}
@code {
private List<Page> _pages;
private List<Module> _modules;
private List<Page> _pages;
private List<Module> _modules;
private int _pagePage = 1;
private int _pageModule = 1;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
@ -105,12 +105,25 @@ else
{
try
{
page.IsDeleted = false;
await PageService.UpdatePageAsync(page);
await logger.LogInformation("Page Restored {Page}", page);
await Load();
StateHasChanged();
NavigationManager.NavigateTo(NavigateUrl());
var validated = true;
if (page.ParentId != null)
{
var parent = _pages.Find(item => item.PageId == page.ParentId);
validated = !parent.IsDeleted;
}
if (validated)
{
page.IsDeleted = false;
await PageService.UpdatePageAsync(page);
await logger.LogInformation("Page Restored {Page}", page);
AddModuleMessage(Localizer["Success.Page.Restore"], MessageType.Success);
await Load();
StateHasChanged();
}
else
{
AddModuleMessage(Localizer["Message.Page.Restore"], MessageType.Warning);
}
}
catch (Exception ex)
{
@ -125,9 +138,9 @@ else
{
await PageService.DeletePageAsync(page.PageId);
await logger.LogInformation("Page Permanently Deleted {Page}", page);
AddModuleMessage(Localizer["Success.Page.Delete"], MessageType.Success);
await Load();
StateHasChanged();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
@ -140,7 +153,7 @@ else
{
try
{
ModuleInstance.ShowProgressIndicator();
ShowProgressIndicator();
foreach (Page page in _pages.Where(item => item.IsDeleted))
{
await PageService.DeletePageAsync(page.PageId);
@ -148,16 +161,16 @@ else
}
await logger.LogInformation("Pages Permanently Deleted");
AddModuleMessage(Localizer["Success.Pages.Delete"], MessageType.Success);
await Load();
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
StateHasChanged();
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting Pages {Error}", ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
}
}
@ -169,6 +182,7 @@ else
pagemodule.IsDeleted = false;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await logger.LogInformation("Module Restored {Module}", module);
AddModuleMessage(Localizer["Success.Module.Restore"], MessageType.Success);
await Load();
StateHasChanged();
}
@ -185,6 +199,7 @@ else
{
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
await logger.LogInformation("Module Permanently Deleted {Module}", module);
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
await Load();
StateHasChanged();
}
@ -199,21 +214,22 @@ else
{
try
{
ModuleInstance.ShowProgressIndicator();
ShowProgressIndicator();
foreach (Module module in _modules.Where(item => item.IsDeleted).ToList())
{
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
}
await logger.LogInformation("Modules Permanently Deleted");
AddModuleMessage(Localizer["Success.Modules.Delete"], MessageType.Success);
await Load();
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting Modules {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Modules.Delete"], MessageType.Error);
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
}
}
private void OnPageChangePage(int page)

View File

@ -1,4 +1,5 @@
@namespace Oqtane.Modules.Admin.Register
@using System.Net
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@ -8,14 +9,14 @@
@if (PageState.Site.AllowRegistration)
{
<AuthorizeView Roles="@RoleNames.Registered">
<Authorizing>
<text>...</text>
</Authorizing>
<Authorized>
if (!_userCreated)
{
if (PageState.User != null)
{
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
</Authorized>
<NotAuthorized>
}
else
{
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
@ -28,25 +29,25 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="Please choose a sufficiently secure password and enter it here" ResourceKey="Password"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
<div class="input-group">
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Enter your password again to confirm it matches the value entered above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
<div class="input-group">
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
<div class="col-sm-9">
<input id="email" class="form-control" @bind="@_email" maxlength="256" required />
<input id="email" class="form-control" @bind="@_email" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -59,9 +60,16 @@
<br />
<button type="button" class="btn btn-primary" @onclick="Register">@Localizer["Register"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
@if (_allowsitelogin)
{
<br />
<br />
<NavLink href="@NavigateUrl("login")">@Localizer["Login"]</NavLink>
}
</form>
</NotAuthorized>
</AuthorizeView>
}
}
}
else
{
@ -79,18 +87,21 @@ else
private string _confirm = string.Empty;
private string _email = string.Empty;
private string _displayname = string.Empty;
private bool _userCreated = false;
private bool _allowsitelogin = true;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
protected override async Task OnInitializedAsync()
{
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
}
protected override void OnParametersSet()
{
_togglepassword = SharedLocalizer["ShowPassword"];
}
{
_togglepassword = SharedLocalizer["ShowPassword"];
}
private async Task Register()
{
@ -120,7 +131,8 @@ else
if (user != null)
{
await logger.LogInformation("User Created {Username} {Email}", _username, _email);
AddModuleMessage(Localizer["Info.User.AccountCreate"], MessageType.Info);
_userCreated = true;
AddModuleMessage(Localizer["Info.User.AccountCreate"], MessageType.Info);
}
else
{
@ -152,7 +164,7 @@ else
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
private void TogglePassword()

View File

@ -12,7 +12,7 @@ else
{
<ActionLink Action="Add" Text="Add Role" Security="SecurityAccessLevel.Edit" ResourceKey="AddRole" />
<Pager Items="@_roles">
<Pager Items="@_roles" SearchProperties="Name">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
@ -20,9 +20,9 @@ else
<th>@SharedLocalizer["Name"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
<td><ActionLink Action="Users" Text="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
<td>@context.Name</td>
</Row>
</Pager>

View File

@ -58,7 +58,7 @@ else
<td>@context.EffectiveDate</td>
<td>@context.ExpiryDate</td>
<td>
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
</td>
</Row>
</Pager>
@ -180,27 +180,28 @@ else
private async Task DeleteUserRole(int UserRoleId)
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
try
{
try
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
if (userrole.Role.Name == RoleNames.Registered)
{
userrole.ExpiryDate = DateTime.UtcNow;
await UserRoleService.UpdateUserRoleAsync(userrole);
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
else
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
AddModuleMessage(Localizer["Confirm.User.RoleRemoved"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
}
else
catch (Exception ex)
{
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message);
AddModuleMessage(Localizer["Error.User.RemoveRole"], MessageType.Error);
}
}
}

View File

@ -0,0 +1,119 @@
@namespace Oqtane.Modules.Admin.Search
@inherits ModuleBase
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="searchprovider" HelpText="Specify the search provider for this site" ResourceKey="SearchProvider">Search Provider: </Label>
<div class="col-sm-9">
<input id="searchprovider" class="form-control" @bind="@_searchProvider" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="enabled" HelpText="Specify if search indexing is enabled" ResourceKey="Enabled">Indexing Enabled? </Label>
<div class="col-sm-9">
<select id="enabled" class="form-select" @bind="@_enabled">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="lastindexedon" HelpText="The date/time which the site was last indexed on" ResourceKey="LastIndexedOn">Last Indexed: </Label>
<div class="col-sm-9">
<input id="lastindexedon" class="form-control" @bind="@_lastIndexedOn" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ignorepages" HelpText="Comma delimited list of pages which should be ignored (based on their path)" ResourceKey="IgnorePages">Ignore Pages: </Label>
<div class="col-sm-9">
<textarea id="ignorepages" class="form-control" @bind="@_ignorePages" rows="3"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ignoreentities" HelpText="Comma delimited list of entities which should be ignored" ResourceKey="IgnoreEntities">Ignore Entities: </Label>
<div class="col-sm-9">
<textarea id="ignoreentities" class="form-control" @bind="@_ignoreEntities" rows="3"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="minimumwordlength" HelpText="Minimum length of a word to be indexed" ResourceKey="MinimumWordLength">Word Length: </Label>
<div class="col-sm-9">
<input id="minimumwordlength" class="form-control" type="number" min="0" step="1" @bind="@_minimumWordLength" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ignorewords" HelpText="Comma delimited list of words which should be ignored" ResourceKey="IgnoreWords">Ignore Words: </Label>
<div class="col-sm-9">
<textarea id="ignorewords" class="form-control" @bind="@_ignoreWords" rows="3"></textarea>
</div>
</div>
</div>
<br /><br />
<button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
<ActionDialog Header="Reindex" Message="Are You Sure You Wish To Reindex Search Content?" Action="Reindex" Class="btn btn-danger" OnClick="@(async () => await Reindex())" ResourceKey="Reindex" />
<br /><br />
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private string _searchProvider;
private string _enabled = "True";
private string _lastIndexedOn = "";
private string _ignorePages = "";
private string _ignoreEntities = "File";
private string _minimumWordLength = "3";
private string _ignoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
protected override async Task OnInitializedAsync()
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_searchProvider = SettingService.GetSetting(settings, "Search_SearchProvider", Constants.DefaultSearchProviderName);
_enabled = SettingService.GetSetting(settings, "Search_Enabled", _enabled);
_lastIndexedOn = SettingService.GetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn);
_ignorePages = SettingService.GetSetting(settings, "Search_IgnorePages", _ignorePages);
_ignoreEntities = SettingService.GetSetting(settings, "Search_IgnoreEntities", _ignoreEntities);
_minimumWordLength = SettingService.GetSetting(settings, "Search_MininumWordLength", _minimumWordLength);
_ignoreWords = SettingService.GetSetting(settings, "Search_IgnoreWords", _ignoreWords);
}
private async Task Save()
{
try
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider);
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled);
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true);
settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true);
settings = SettingService.SetSetting(settings, "Search_MininumWordLength", _minimumWordLength, true);
settings = SettingService.SetSetting(settings, "Search_IgnoreWords", _ignoreWords, true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
AddModuleMessage(Localizer["Success.Save"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Search Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Save"], MessageType.Error);
}
}
private async Task Reindex()
{
try
{
_lastIndexedOn = DateTime.MinValue.ToString();
await Save();
AddModuleMessage(Localizer["Message.Reindex"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Saving Search Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Save"], MessageType.Error);
}
}
}

View File

@ -0,0 +1,142 @@
@using Oqtane.Services
@using System.Net
@namespace Oqtane.Modules.Admin.SearchResults
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ISearchResultsService SearchResultsService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@attribute [StreamRendering] // attribute allows the progress indicator to be displayed
<div class="search-result-container">
<div class="row">
<div class="col">
<form method="post" @formname="SearchResultsForm" @onsubmit="Search" data-enhance>
<div class="input-group mb-3">
<span class="input-group-text">@Localizer["SearchLabel"]</span>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<input type="text" name="keywords" class="form-control shadow-none" maxlength="50"
aria-label="Keywords"
placeholder="@Localizer["SearchPlaceholder"]"
@bind="@_keywords">
<button class="btn btn-primary" type="submit">@SharedLocalizer["Search"]</button>
<a class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Reset"]</a>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 mb-3">
@if (_loading)
{
<div class="app-progress-indicator"></div>
}
else
{
@if (_searchResults != null && _searchResults.Results != null)
{
if (_searchResults.Results.Any())
{
<Pager Items="@_searchResults?.Results"
Format="Grid"
Columns="1"
Toolbar="Bottom"
Parameters="@($"q={_keywords}")">
<Row>
<div class="search-item mb-2">
<h4 class="mb-1"><a href="@context.Url">@context.Title</a></h4>
<p class="mb-0 text-muted">@((MarkupString)context.Snippet)</p>
</div>
</Row>
</Pager>
}
else
{
<div class="alert alert-info show mt-3" role="alert">
@Localizer["NoResult"]
</div>
}
}
<div class="clearfix"></div>
}
</div>
</div>
</div>
@code {
public override string RenderMode => RenderModes.Static;
private string _includeEntities;
private string _excludeEntities;
private string _fromDate;
private string _toDate;
private string _pageSize;
private string _sortField;
private string _sortOrder;
private string _bodyLength;
private string _keywords;
private SearchResults _searchResults;
private bool _loading;
[SupplyParameterFromForm(FormName = "SearchResultsForm")]
public string KeyWords { get => ""; set => _keywords = value; }
protected override async Task OnInitializedAsync()
{
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
_fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", DateTime.MinValue.ToString());
_toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", DateTime.MaxValue.ToString());
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", int.MaxValue.ToString());
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
if (_keywords == null && PageState.QueryString.ContainsKey("q"))
{
_keywords = WebUtility.UrlDecode(PageState.QueryString["q"]);
await PerformSearch();
}
}
private void Search()
{
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, $"page=1&q={WebUtility.UrlEncode(_keywords)}"));
}
private async Task PerformSearch()
{
_loading = true;
StateHasChanged();
if (!string.IsNullOrEmpty(_keywords))
{
var searchQuery = new SearchQuery
{
SiteId = PageState.Site.SiteId,
Alias = PageState.Alias,
Keywords = _keywords,
IncludeEntities = _includeEntities,
ExcludeEntities = _excludeEntities,
FromDate = (!string.IsNullOrEmpty(_fromDate)) ? DateTime.Parse(_fromDate) : DateTime.MinValue,
ToDate = (!string.IsNullOrEmpty(_toDate)) ? DateTime.Parse(_toDate) : DateTime.MaxValue,
PageSize = (!string.IsNullOrEmpty(_pageSize)) ? int.Parse(_pageSize) : int.MaxValue,
PageIndex = 0,
SortField = (!string.IsNullOrEmpty(_sortField)) ? (SearchSortField)Enum.Parse(typeof(SearchSortField), _sortField) : SearchSortField.Relevance,
SortOrder = (!string.IsNullOrEmpty(_sortOrder)) ? (SearchSortOrder)Enum.Parse(typeof(SearchSortOrder), _sortOrder) : SearchSortOrder.Descending,
BodyLength = (!string.IsNullOrEmpty(_bodyLength)) ? int.Parse(_bodyLength) : 255
};
_searchResults = await SearchResultsService.GetSearchResultsAsync(searchQuery);
}
else
{
AddModuleMessage(Localizer["NoCriteria"], MessageType.Info, "bottom");
}
_loading = false;
StateHasChanged();
}
}

View File

@ -0,0 +1,19 @@
using Oqtane.Documentation;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Modules.Admin.SearchResults
{
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Search Results",
Description = "Search Results",
Categories = "Admin",
Version = Constants.Version,
SettingsType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"
};
}
}

View File

@ -0,0 +1,123 @@
@namespace Oqtane.Modules.Admin.SearchResults
@inherits ModuleBase
@inject ISettingService SettingService
@implements Oqtane.Interfaces.ISettingsControl
@inject IStringLocalizer<Settings> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="includeentities" ResourceKey="IncludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to include in the search results. By default all entities will be included.">Include Entities: </Label>
<div class="col-sm-9">
<input id="includeentities" type="text" class="form-control" @bind="@_includeEntities" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="excludeentities" ResourceKey="ExcludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to exclude from search results. By default no entities will be excluded.">Exclude Entities: </Label>
<div class="col-sm-9">
<input id="excludeentities" class="form-control" @bind="@_excludeEntities" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="daterange" ResourceKey="DateRange" ResourceType="@resourceType" HelpText="Enter the date range for search results. The default includes all content.">Date Range: </Label>
<div class="col-sm-9">
<div class="input-group">
<input type="date" class="form-control" @bind="@_fromDate" />
<span class="input-group-text">@Localizer["To"]</span>
<input type="date" class="form-control" @bind="@_toDate" />
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="pagesize" ResourceKey="PageSize" ResourceType="@resourceType" HelpText="The maximum number of search results to retrieve. The default is unlimited.">Page Size: </Label>
<div class="col-sm-9">
<input id="pagesize" type="text" class="form-control" @bind="@_pageSize" />
</div>
</div>
<hr />
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="sortfield" ResourceKey="SortField" ResourceType="@resourceType" HelpText="Specify the default sort field">Sort By: </Label>
<div class="col-sm-9">
<select id="softfield" class="form-select" @bind="@_sortField">
<option value="Relevance">@Localizer["Relevance"]</option>
<option value="Title">@Localizer["Title"]</option>
<option value="LastModified">@Localizer["LastModified"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="sortorder" ResourceKey="SortOrder" ResourceType="@resourceType" HelpText="Specify the default sort order">Sort Order: </Label>
<div class="col-sm-9">
<select id="softorder" class="form-select" @bind="@_sortOrder">
<option value="Ascending">@Localizer["Ascending"]</option>
<option value="Descending">@Localizer["Descending"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="bodylength" ResourceKey="BodyLength" ResourceType="@resourceType" HelpText="The number of characters displayed for each search result summary. The default is 255 characters.">Body Size: </Label>
<div class="col-sm-9">
<input id="bodylength" type="text" class="form-control" @bind="@_bodyLength" />
</div>
</div>
</div>
</form>
@code {
private string resourceType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"; // for localization
private ElementReference form;
private bool validated = false;
private string _includeEntities;
private string _excludeEntities;
private DateTime? _fromDate = null;
private DateTime? _toDate = null;
private string _pageSize;
private string _sortField;
private string _sortOrder;
private string _bodyLength;
protected override void OnInitialized()
{
try
{
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
var fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", "");
_fromDate = (string.IsNullOrEmpty(fromDate)) ? null : DateTime.Parse(fromDate);
var toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", "");
_toDate = (string.IsNullOrEmpty(toDate)) ? null : DateTime.Parse(toDate);
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", "");
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
public async Task UpdateSettings()
{
try
{
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
settings = SettingService.SetSetting(settings, "SearchResults_IncludeEntities", _includeEntities);
settings = SettingService.SetSetting(settings, "SearchResults_ExcludeEntities", _excludeEntities);
settings = SettingService.SetSetting(settings, "SearchResults_From", _fromDate.ToString());
settings = SettingService.SetSetting(settings, "SearchResults_To", _toDate.ToString());
settings = SettingService.SetSetting(settings, "SearchResults_PageSize", _pageSize);
settings = SettingService.SetSetting(settings, "SearchResults_SortField", _sortField);
settings = SettingService.SetSetting(settings, "SearchResults_SortOrder", _sortOrder);
settings = SettingService.SetSetting(settings, "SearchResults_BodyLength", _bodyLength);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ else
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
<div class="col-sm-9">
<select id="defaultTheme" class="form-select" @onchange="(e => ThemeChanged(e))" required>
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
<option value="-">&lt;@Localizer["Theme.Select"]&gt;</option>
@foreach (var theme in _themes)
{
@ -58,19 +58,6 @@ else
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="adminContainer" HelpText="Select the admin container for the site" ResourceKey="AdminContainer">Admin Container: </Label>
<div class="col-sm-9">
<select id="adminContainer" class="form-select" @bind="@_admincontainertype" required>
<option value="-">&lt;@Localizer["Container.Select"]&gt;</option>
<option value="">&lt;@Localizer["DefaultContainer.Admin"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="siteTemplate" HelpText="Select the site template" ResourceKey="SiteTemplate">Site Template: </Label>
<div class="col-sm-9">
@ -84,28 +71,29 @@ else
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runtime" HelpText="The runtime hosting model" ResourceKey="Runtime">Runtime: </Label>
<Label Class="col-sm-3" For="rendermode" HelpText="The default render mode for the site" ResourceKey="Rendermode">Render Mode: </Label>
<div class="col-sm-9">
<select id="runtime" class="form-select" @bind="@_runtime" required>
<option value="Server">@SharedLocalizer["BlazorServer"]</option>
<option value="WebAssembly">@SharedLocalizer["BlazorWebAssembly"]</option>
<option value="Hybrid">@SharedLocalizer["BlazorHybrid"]</option>
</select>
<select id="rendermode" class="form-select" @bind="@_rendermode" required>
<option value="@RenderModes.Interactive">@(SharedLocalizer["RenderMode" + @RenderModes.Interactive])</option>
<option value="@RenderModes.Static">@(SharedLocalizer["RenderMode" + @RenderModes.Static])</option>
<option value="@RenderModes.Headless">@(SharedLocalizer["RenderMode" + @RenderModes.Headless])</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if the site should be prerendered (for search crawlers, etc...)" ResourceKey="Prerender">Prerender? </Label>
<Label Class="col-sm-3" For="runtime" HelpText="The render mode for UI components which require interactivity" ResourceKey="Runtime">Interactivity: </Label>
<div class="col-sm-9">
<select id="prerender" class="form-select" @bind="@_prerender" required>
<option value="Prerendered">@SharedLocalizer["Yes"]</option>
<option value="">@SharedLocalizer["No"]</option>
<select id="runtime" class="form-select" @bind="@_runtime" required>
<option value="@Runtimes.Server">@(SharedLocalizer["Runtime" + @Runtimes.Server])</option>
<option value="@Runtimes.WebAssembly">@(SharedLocalizer["Runtime" + @Runtimes.WebAssembly])</option>
<option value="@Runtimes.Auto">@(SharedLocalizer["Runtime" + @Runtimes.Auto])</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="tenant" HelpText="Select the database for the site" ResourceKey="Tenant">Database: </Label>
<div class="col-sm-9">
<select id="tenant" class="form-select" @onchange="(e => TenantChanged(e))" required>
<select id="tenant" class="form-select" value="@_tenantid" @onchange="(e => TenantChanged(e))" required>
<option value="-">&lt;@Localizer["Tenant.Select"]&gt;</option>
<option value="+">&lt;@Localizer["Tenant.Add"]&gt;</option>
@foreach (Tenant tenant in _tenants)
@ -121,7 +109,7 @@ else
<hr class="app-rule" />
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the database" ResourceKey="TenantName">Name: </Label>
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the database. Note that this will be the tenant name which is used within the framework to identify the database." ResourceKey="TenantName">Name: </Label>
<div class="col-sm-9">
<input id="name" class="form-control" @bind="@_tenantName" maxlength="100" required />
</div>
@ -188,179 +176,191 @@ else
}
@code {
private List<Database> _databases;
private ElementReference form;
private bool validated = false;
private string _databaseName;
private Type _databaseConfigType;
private object _databaseConfig;
private RenderFragment DatabaseConfigComponent { get; set; }
private bool _showConnectionString = false;
private string _connectionString = string.Empty;
private List<Database> _databases;
private ElementReference form;
private bool validated = false;
private string _databaseName;
private Type _databaseConfigType;
private object _databaseConfig;
private RenderFragment DatabaseConfigComponent { get; set; }
private bool _showConnectionString = false;
private string _connectionString = string.Empty;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<SiteTemplate> _siteTemplates;
private List<Tenant> _tenants;
private string _tenantid = "-";
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<SiteTemplate> _siteTemplates;
private List<Tenant> _tenants;
private string _tenantid = "-";
private string _tenantName = string.Empty;
private string _tenantName = string.Empty;
private string _hostusername = string.Empty;
private string _hostpassword = string.Empty;
private string _hostusername = string.Empty;
private string _hostpassword = string.Empty;
private string _name = string.Empty;
private string _urls = string.Empty;
private string _themetype = "-";
private string _containertype = "-";
private string _admincontainertype = "";
private string _sitetemplatetype = "-";
private string _runtime = "Server";
private string _prerender = "Prerendered";
private string _name = string.Empty;
private string _urls = string.Empty;
private string _themetype = "-";
private string _containertype = "-";
private string _sitetemplatetype = "-";
private string _rendermode = RenderModes.Static;
private string _runtime = Runtimes.Server;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
_tenants = await TenantService.GetTenantsAsync();
_urls = PageState.Alias.Name;
_themeList = await ThemeService.GetThemesAsync();
_themes = ThemeService.GetThemeControls(_themeList);
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
protected override async Task OnInitializedAsync()
{
_tenants = await TenantService.GetTenantsAsync();
if (_tenants.Any(item => item.Name == TenantNames.Master))
{
_tenantid = _tenants.First(item => item.Name == TenantNames.Master).TenantId.ToString();
}
_urls = PageState.Alias.Name;
_themeList = await ThemeService.GetThemesAsync();
_themes = ThemeService.GetThemeControls(_themeList);
if (_themes.Any(item => item.TypeName == Constants.DefaultTheme))
{
_themetype = Constants.DefaultTheme;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = _containers.First().TypeName;
}
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
if (_siteTemplates.Any(item => item.TypeName == Constants.DefaultSiteTemplate))
{
_sitetemplatetype = Constants.DefaultSiteTemplate;
}
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
}
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
}
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
}
}
private void LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
if (database != null)
{
_databaseConfigType = Type.GetType(database.ControlType);
DatabaseConfigComponent = builder =>
{
builder.OpenComponent(0, _databaseConfigType);
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
builder.CloseComponent();
};
}
}
private void LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
if (database != null)
{
_databaseConfigType = Type.GetType(database.ControlType);
DatabaseConfigComponent = builder =>
{
builder.OpenComponent(0, _databaseConfigType);
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
builder.CloseComponent();
};
}
}
private void TenantChanged(ChangeEventArgs e)
{
_tenantid = (string)e.Value;
if (string.IsNullOrEmpty(_tenantName))
{
_tenantName = _name;
}
StateHasChanged();
}
private void TenantChanged(ChangeEventArgs e)
{
_tenantid = (string)e.Value;
if (string.IsNullOrEmpty(_tenantName))
{
_tenantName = _name;
}
StateHasChanged();
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
_themetype = (string)e.Value;
if (_themetype != "-")
{
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
_themetype = (string)e.Value;
if (_themetype != "-")
{
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = _containers.First().TypeName;
}
else
{
_containers = new List<ThemeControl>();
else
{
_containers = new List<ThemeControl>();
_containertype = "-";
}
_admincontainertype = "";
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
AddModuleMessage(Localizer["Error.Theme.LoadContainers"], MessageType.Error);
}
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
AddModuleMessage(Localizer["Error.Theme.LoadContainers"], MessageType.Error);
}
}
private async Task SaveSite()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
{
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
var duplicates = new List<string>();
var aliases = await AliasService.GetAliasesAsync();
foreach (string name in _urls.Split(',', StringSplitOptions.RemoveEmptyEntries))
{
if (aliases.Exists(item => item.Name == name))
{
duplicates.Add(name);
}
}
private async Task SaveSite()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
{
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
var duplicates = new List<string>();
var aliases = await AliasService.GetAliasesAsync();
foreach (string name in _urls.Split(',', StringSplitOptions.RemoveEmptyEntries))
{
if (aliases.Exists(item => item.Name == name))
{
duplicates.Add(name);
}
}
if (duplicates.Count == 0)
{
InstallConfig config = new InstallConfig();
if (duplicates.Count == 0)
{
InstallConfig config = new InstallConfig();
if (_tenantid == "+")
{
if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName))
{
// validate host credentials
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _hostusername;
user.Password = _hostpassword;
user.LastIPAddress = PageState.RemoteIPAddress;
user = await UserService.LoginUserAsync(user, false, false);
if (_tenantid == "+")
{
if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName))
{
// validate host credentials
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _hostusername;
user.Password = _hostpassword;
user.LastIPAddress = PageState.RemoteIPAddress;
user = await UserService.LoginUserAsync(user, false, false);
if (user.IsAuthenticated)
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
if (connectionString != "")
{
config.TenantName = _tenantName;
config.DatabaseType = database.DBType;
config.ConnectionString = connectionString;
config.HostUsername = _hostusername;
config.HostUsername = _hostusername;
config.HostPassword = _hostpassword;
config.HostEmail = user.Email;
config.HostName = user.DisplayName;
@ -399,10 +399,10 @@ else
config.Aliases = _urls;
config.DefaultTheme = _themetype;
config.DefaultContainer = _containertype;
config.DefaultAdminContainer = _admincontainertype;
config.DefaultAdminContainer = "";
config.SiteTemplate = _sitetemplatetype;
config.RenderMode = _rendermode;
config.Runtime = _runtime;
config.RenderMode = _runtime + _prerender;
ShowProgressIndicator();

View File

@ -14,7 +14,7 @@ else
{
<ActionLink Action="Add" Text="Add Site" ResourceKey="AddSite" />
<Pager Items="@_sites">
<Pager Items="@_sites" SearchProperties="Name">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
@ -48,11 +48,25 @@ else
private void Edit(string name)
{
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true);
if (PageState.Alias.Name == name)
{
NavigationManager.NavigateTo("/admin/site");
}
else
{
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true);
}
}
private void Browse(string name)
{
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true);
if (PageState.Alias.Name == name)
{
NavigationManager.NavigateTo(PageState.Alias.Path + "/");
}
else
{
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true);
}
}
}

View File

@ -83,24 +83,15 @@ else
{
@if (_connection != "-")
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
<div class="col-sm-9">
@if (_databases != null)
{
<select id="databasetype" class="form-select" @bind="@_databasetype" required>
<option value="-">&lt;@Localizer["Type.Select"]&gt;</option>
@foreach (var database in _databases)
{
<option value="@database.Name">@Localizer[@database.Name]</option>
}
</select>
}
</div>
</div>
@if (!string.IsNullOrEmpty(_tenant))
{
<div class="row mb-1 align-items-center">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
<div class="col-sm-9">
<input id="databasetype" class="form-control" @bind="@_databasetype" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="tenant" HelpText="The database using this connection" ResourceKey="Tenant">Database: </Label>
<div class="col-sm-9">
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
@ -204,12 +195,12 @@ else
{
_connectionstring = _connections[_connection].ToString();
_tenant = "";
_databasetype = "-";
_databasetype = "";
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
if (tenant != null)
{
_tenant = tenant.Name;
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType).Name;
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType && item.Name != "LocalDB").Name;
}
}
else

View File

@ -26,6 +26,12 @@
<input id="osversion" class="form-control" @bind="@_osversion" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="process" HelpText="Indicates if the current process is 32 bit or 64 bit" ResourceKey="Process">Process: </Label>
<div class="col-sm-9">
<input id="process" class="form-control" @bind="@_process" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="machinename" HelpText="Machine Name" ResourceKey="MachineName">Machine Name: </Label>
<div class="col-sm-9">
@ -62,12 +68,6 @@
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="tickcount" HelpText="Amount Of Time The Service Has Been Available And Operational" ResourceKey="TickCount">Service Uptime: </Label>
<div class="col-sm-9">
<input id="tickcount" class="form-control" @bind="@_tickcount" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="workingset" HelpText="Memory Allocation Of Service (in MB)" ResourceKey="WorkingSet">Memory Allocation: </Label>
<div class="col-sm-9">
@ -133,16 +133,30 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packageregistryurl" HelpText="Specify The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation." ResourceKey="PackageManager">Package Manager: </Label>
<Label Class="col-sm-3" For="cachecontrol" HelpText="Provide a Cache-Control directive for static assets. For example 'public, max-age=60' indicates that static assets should be cached for 60 seconds. A blank value indicates caching is not enabled." ResourceKey="CacheControl">Static Asset Caching: </Label>
<div class="col-sm-9">
<input id="cachecontrol" class="form-control" @bind="@_cachecontrol" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packageregistryurl" HelpText="Specify The Url Of The Package Manager Service For Installing Modules, Themes, And Translations. If This Field Is Blank It Means The Package Manager Service Is Disabled For This Installation." ResourceKey="PackageManager">Package Manager Url: </Label>
<div class="col-sm-9">
<input id="packageregistryurl" class="form-control" @bind="@_packageregistryurl" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packageregistryemail" HelpText="Specify The Email Address Of The User Account Used For Interacting With The Package Manager Service. This Account Is Used For Managing Packages Across Multiple Installations." ResourceKey="PackageManagerEmail">Package Manager Email: </Label>
<div class="col-sm-9">
<input id="packageregistryemail" class="form-control" @bind="@_packageregistryemail" />
</div>
</div>
</div>
<br /><br />
<button type="button" class="btn btn-success" @onclick="SaveConfig">@SharedLocalizer["Save"]</button>&nbsp;
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Access.ApiFramework"]</a>&nbsp;
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
<br /><br />
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Swagger"]</a>&nbsp;
<a class="btn btn-secondary" href="api/endpoint" target="_new">@Localizer["Endpoints"]</a>
</TabPanel>
<TabPanel Name="Log" Heading="Log" ResourceKey="Log">
<div class="container">
@ -165,13 +179,13 @@
private string _version = string.Empty;
private string _clrversion = string.Empty;
private string _osversion = string.Empty;
private string _machinename = string.Empty;
private string _process = string.Empty;
private string _machinename = string.Empty;
private string _ipaddress = string.Empty;
private string _environment = string.Empty;
private string _contentrootpath = string.Empty;
private string _webrootpath = string.Empty;
private string _servertime = string.Empty;
private string _tickcount = string.Empty;
private string _workingset = string.Empty;
private string _installationid = string.Empty;
@ -179,9 +193,11 @@
private string _logginglevel = string.Empty;
private string _notificationlevel = string.Empty;
private string _swagger = string.Empty;
private string _cachecontrol = string.Empty;
private string _packageregistryurl = string.Empty;
private string _packageregistryemail = string.Empty;
private string _log = string.Empty;
private string _log = string.Empty;
protected override async Task OnInitializedAsync()
{
@ -192,13 +208,13 @@
{
_clrversion = systeminfo["CLRVersion"].ToString();
_osversion = systeminfo["OSVersion"].ToString();
_machinename = systeminfo["MachineName"].ToString();
_process = systeminfo["Process"].ToString();
_machinename = systeminfo["MachineName"].ToString();
_ipaddress = systeminfo["IPAddress"].ToString();
_environment = systeminfo["Environment"].ToString();
_contentrootpath = systeminfo["ContentRootPath"].ToString();
_webrootpath = systeminfo["WebRootPath"].ToString();
_servertime = systeminfo["ServerTime"].ToString() + " UTC";
_tickcount = TimeSpan.FromMilliseconds(Convert.ToInt64(systeminfo["TickCount"].ToString())).ToString();
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
}
@ -209,9 +225,11 @@
_detailederrors = systeminfo["DetailedErrors"].ToString();
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
_swagger = systeminfo["UseSwagger"].ToString();
_swagger = systeminfo["UseSwagger"].ToString();
_cachecontrol = systeminfo["CacheControl"].ToString();
_packageregistryurl = systeminfo["PackageRegistryUrl"].ToString();
}
_packageregistryemail = systeminfo["PackageRegistryEmail"].ToString();
}
systeminfo = await SystemService.GetSystemInfoAsync("log");
if (systeminfo != null)
@ -229,8 +247,10 @@
settings.Add("Logging:LogLevel:Default", _logginglevel);
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
settings.Add("UseSwagger", _swagger);
settings.Add("PackageRegistryUrl", _packageregistryurl);
await SystemService.UpdateSystemInfoAsync(settings);
settings.Add("CacheControl", _cachecontrol);
settings.Add("PackageRegistryUrl", _packageregistryurl);
settings.Add("PackageRegistryEmail", _packageregistryemail);
await SystemService.UpdateSystemInfoAsync(settings);
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
}
catch (Exception ex)

View File

@ -66,6 +66,7 @@
<div class="container-fluid px-0">
<div class="row g-0 mb-2">
<div class="col-4">
<a href="@context.ProductUrl" target="_blank">
@if (context.LogoUrl != null)
{
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
@ -74,6 +75,7 @@
{
<img src="/package.png" class="img-fluid" alt="@context.Name" />
}
</a>
</div>
<div class="col-8 text-end">
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
@ -123,7 +125,7 @@
<TabPanel Name="Upload" ResourceKey="Upload">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation." ResourceKey="Theme">Theme: </Label>
<Label Class="col-sm-3" HelpText="Upload one or more theme packages." ResourceKey="Theme">Theme: </Label>
<div class="col-sm-9">
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
</div>

View File

@ -45,24 +45,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this theme was installed. This value must be specified within the theme's ITheme interface specification." ResourceKey="PackageName">Package Name: </Label>
<div class="col-sm-9">
@if (!string.IsNullOrEmpty(_packagename))
{
<div class="input-group">
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
@if (string.IsNullOrEmpty(_packageurl))
{
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
}
else
{
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
}
</div>
}
else
{
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
}
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -116,7 +99,6 @@
private string _name;
private string _version;
private string _packagename = "";
private string _packageurl = "";
private string _owner = "";
private string _url = "";
private string _contact = "";
@ -185,27 +167,4 @@
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
}
}
private async Task ValidatePackage()
{
try
{
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
{
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
}
else
{
_packageurl = package.PackageUrl;
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
}
}
}

View File

@ -4,6 +4,7 @@
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@inject IPackageService PackageService
@inject ISiteService SiteService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -19,6 +20,7 @@ else
<Pager Items="@_themes">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th>
@ -29,13 +31,14 @@ else
<th>&nbsp;</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
<td>
@if (context.AssemblyName != Constants.ClientId)
{
{
<ActionDialog Header="Delete Theme" Message="@string.Format(Localizer["Confirm.Theme.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" ResourceKey="DeleteTheme" />
}
}
</td>
<td><NavLink class="btn btn-secondary" href="@NavigateUrl("admin/site")">@Localizer["Assign"]</NavLink></td>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
@ -63,7 +66,6 @@ else
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
}
</td>
<td></td>
</Row>
</Pager>
}

View File

@ -54,6 +54,8 @@
}
else
{
AddModuleMessage(Localizer["Disclaimer.Text"], MessageType.Warning);
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
if (packages != null)
{
@ -97,13 +99,16 @@
{
try
{
ShowProgressIndicator();
await PackageService.DownloadPackageAsync(packageid, version);
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version);
HideProgressIndicator();
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Framework Package {Error}", ex.Message);
HideProgressIndicator();
AddModuleMessage(Localizer["Error.Framework.Download"], MessageType.Error);
}
}

View File

@ -3,6 +3,7 @@
@inject NavigationManager NavigationManager
@inject IUrlMappingService UrlMappingService
@inject ISiteService SiteService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -28,7 +29,7 @@ else
</div>
</div>
<br/>
<Pager Items="@_urlMappings">
<Pager Items="@_urlMappings" SearchProperties="Url">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
@ -37,7 +38,7 @@ else
<th>@Localizer["Requested"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
<td>
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
@ -62,7 +63,13 @@ else
</select>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of days of broken urls to retain" ResourceKey="Retention">Retention (Days): </Label>
<div class="col-sm-9">
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
</TabPanel>
@ -73,6 +80,7 @@ else
private bool _mapped = true;
private List<UrlMapping> _urlMappings;
private string _capturebrokenurls;
private int _retention = 30;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
@ -80,7 +88,10 @@ else
{
await GetUrlMappings();
_capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString();
}
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_retention = int.Parse(SettingService.GetSetting(settings, "UrlMappingRetention", "30"));
}
private async void MappedChanged(ChangeEventArgs e)
{
@ -124,7 +135,12 @@ else
var site = PageState.Site;
site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls);
await SiteService.UpdateSiteAsync(site);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
settings = SettingService.SetSetting(settings, "UrlMappingRetention", _retention.ToString(), true);
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
}
catch (Exception ex)
{

View File

@ -2,6 +2,7 @@
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IUserRoleService UserRoleService
@inject INotificationService NotificationService
@inject IStringLocalizer<Add> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -10,10 +11,10 @@
{
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="to" HelpText="Enter the username you wish to send a message to" ResourceKey="To">To: </Label>
<Label Class="col-sm-3" For="to" HelpText="Enter the user you wish to send a message to" ResourceKey="To">To: </Label>
<div class="col-sm-9">
<input id="to" class="form-control" @bind="@username" />
</div>
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["Username.Enter"]" @ref="username" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="subject" HelpText="Enter the subject of the message" ResourceKey="Subject">Subject: </Label>
@ -30,11 +31,11 @@
</div>
<br/>
<button type="button" class="btn btn-primary" @onclick="Send">@SharedLocalizer["Send"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
}
@code {
private string username = "";
private AutoComplete username;
private string subject = "";
private string body = "";
@ -42,21 +43,35 @@
public override string Title => "Send Notification";
private async Task<Dictionary<string, string>> GetUsers(string filter)
{
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
return users.Where(item => item.User.Username.Contains(filter, StringComparison.OrdinalIgnoreCase))
.ToDictionary(item => item.UserId.ToString(), item => item.User.Username);
}
private async Task Send()
{
try
{
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
if (user != null)
if (!string.IsNullOrEmpty(username.Key) && !string.IsNullOrEmpty(subject))
{
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body);
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
NavigationManager.NavigateTo(NavigateUrl());
var user = await UserService.GetUserAsync(int.Parse(username.Key), ModuleState.SiteId);
if (user != null)
{
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body);
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
else
{
AddModuleMessage(Localizer["Message.User.Invalid"], MessageType.Warning);
}
}
else
{
AddModuleMessage(Localizer["Message.User.Invalid"], MessageType.Warning);
AddModuleMessage(Localizer["Message.Required"], MessageType.Warning);
}
}
catch (Exception ex)

View File

@ -1,4 +1,5 @@
@namespace Oqtane.Modules.Admin.UserProfile
@using System.Net
@using System.Text.RegularExpressions;
@inherits ModuleBase
@inject NavigationManager NavigationManager
@ -8,21 +9,23 @@
@inject INotificationService NotificationService
@inject IFileService FileService
@inject IFolderService FolderService
@inject IJSRuntime jsRuntime
@inject IServiceProvider ServiceProvider
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@if (PageState.User != null && photo != null)
@if (_initialized)
{
<img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
}
else
{
<br />
}
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
@if (profiles != null && settings != null)
{
@if (PageState.User != null && photo != null)
{
<img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
}
else
{
<br />
}
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
<div class="container">
<div class="row mb-1 align-items-center">
@ -33,34 +36,34 @@ else
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="If you wish to change your password you can enter it here. Please choose a sufficiently secure password." ResourceKey="Password"></Label>
<div class="col-sm-9">
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
@if (allowtwofactor)
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
<div class="col-sm-9">
<select id="twofactor" class="form-select" @bind="@twofactor" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
}
@if (allowtwofactor)
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
<div class="col-sm-9">
<select id="twofactor" class="form-select" @bind="@twofactor" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
<div class="col-sm-9">
@ -76,18 +79,16 @@ else
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="@photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" Filter="@Constants.ImageFiles" ShowFolders="false" ShowFiles="true" UploadMultiple="false" FolderId="@folderid" @ref="filemanager" />
<FileManager FileId="@photofileid" Filter="@PageState.Site.ImageFiles" ShowFolders="false" ShowFiles="true" UploadMultiple="false" FolderId="@folderid" @ref="filemanager" />
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
@if (profiles != null && settings != null)
{
<button type="button" class="btn btn-danger" @onclick="Logout">@Localizer["Logout Everywhere"]</button>
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
<div class="container">
<div class="row mb-1 align-items-center">
@foreach (Profile profile in profiles)
@ -107,29 +108,98 @@ else
<div class="col-sm-9">
@if (!string.IsNullOrEmpty(p.Options))
{
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
{
<option value="@option" selected>@option</option>
}
else
{
<option value="@option">@option</option>
}
}
</select>
}
else
{
@if (p.IsRequired)
@if (!string.IsNullOrEmpty(p.Autocomplete))
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete">
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
{
<option value="@option" selected>@option</option>
}
else
{
<option value="@option">@option</option>
}
}
</select>
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
{
<option value="@option" selected>@option</option>
}
else
{
<option value="@option">@option</option>
}
}
</select>
}
}
else
{
@if (p.Rows == 1)
{
if (!string.IsNullOrEmpty(p.Autocomplete))
{
@if (p.IsRequired)
{
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
else
{
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
}
else
{
@if (p.IsRequired)
{
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
else
{
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
}
}
else
{
if (!string.IsNullOrEmpty(p.Autocomplete))
{
@if (p.IsRequired)
{
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
else
{
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
}
else
{
@if (p.IsRequired)
{
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
else
{
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"
@attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
}
}
}
</div>
@ -140,134 +210,151 @@ else
</div>
<button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
}
</TabPanel>
<TabPanel Name="Notifications" ResourceKey="Notifications">
@if (notifications != null)
{
</TabPanel>
<TabPanel Name="Notifications" ResourceKey="Notifications">
<ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="SendNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" />
<br />
<br />
<select class="form-select" @onchange="(e => FilterChanged(e))">
<option value="to">@Localizer["Inbox"]</option>
<option value="from">@Localizer["Items.Sent"]</option>
</select>
<br />
<ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="SendNotification" />
<br /><br />
@if (filter == "to")
{
<Pager Items="@notifications">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["From"]</th>
<th>@Localizer["Subject"]</th>
<th>@Localizer["Received"]</th>
</Header>
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
@if (context.IsRead)
{
<td>@context.FromDisplayName</td>
<td>@context.Subject</td>
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
}
else
{
<td><b>@context.FromDisplayName</b></td>
<td><b>@context.Subject</b></td>
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
}
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input))
{
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
}
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
}
@if (notifications.Any())
{
<Pager Items="@notifications">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["From"]</th>
<th>@Localizer["Subject"]</th>
<th>@Localizer["Received"]</th>
</Header>
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
@if (context.IsRead)
{
@notificationSummary
<td>@(string.IsNullOrEmpty(context.FromDisplayName) ? SharedLocalizer["System"] : context.FromDisplayName)</td>
<td>@context.Subject</td>
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
}
else
{
<b>@notificationSummary</b>
<td><b>@(string.IsNullOrEmpty(context.FromDisplayName) ? SharedLocalizer["System"] : context.FromDisplayName)</b></td>
<td><b>@context.Subject</b></td>
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
}
</td>
</Detail>
</Pager>
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input))
{
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
}
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
}
@if (context.IsRead)
{
@notificationSummary
}
else
{
<b>@notificationSummary</b>
}
</td>
</Detail>
</Pager>
<br />
<ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
}
else
{
<div class="no-notifications-text">
@Localizer["NoNotificationsReceived.Text"]
</div>
}
}
else
{
<Pager Items="@notifications">
<Header>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>@Localizer["To"]</th>
<th>@Localizer["Subject"]</th>
<th>@Localizer["Sent"]</th>
</Header>
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
@if (notifications.Any())
{
<Pager Items="@notifications">
<Header>
<th style="width: 1px;"></th>
<th style="width: 1px;"></th>
<th>@Localizer["To"]</th>
<th>@Localizer["Subject"]</th>
<th>@Localizer["Sent"]</th>
</Header>
<Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
@if (context.IsRead)
{
<td>@context.ToDisplayName</td>
<td>@context.Subject</td>
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
}
else
{
<td><b>@context.ToDisplayName</b></td>
<td><b>@context.Subject</b></td>
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
}
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input))
{
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
}
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
}
@if (context.IsRead)
{
@notificationSummary
<td>@context.ToDisplayName</td>
<td>@context.Subject</td>
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
}
else
else
{
<b>@notificationSummary</b>
}
</td>
</Detail>
</Pager>
<td><b>@context.ToDisplayName</b></td>
<td><b>@context.Subject</b></td>
<td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
}
</Row>
<Detail>
<td colspan="2"></td>
<td colspan="3">
@{
string input = "___";
if (context.Body.Contains(input))
{
context.Body = context.Body.Split(input)[0];
context.Body = context.Body.Replace("\n", "");
context.Body = context.Body.Replace("\r", "");
}
notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
}
@if (context.IsRead)
{
@notificationSummary
}
else
{
<b>@notificationSummary</b>
}
</td>
</Detail>
</Pager>
<br />
<ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
}
else
{
<div class="no-notifications-text">
@Localizer["NoNotificationsSent.Text"]
</div>
}
}
@if (notifications.Any())
{
<br />
<ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
}
}
</TabPanel>
</TabStrip>
<br /><br />
</TabPanel>
</TabStrip>
<br />
<br />
}
@code {
private bool _initialized = false;
private string _passwordrequirements;
private string username = string.Empty;
private string _password = string.Empty;
@ -282,24 +369,25 @@ else
private int folderid = -1;
private int photofileid = -1;
private File photo = null;
private string _ImageFiles = string.Empty;
private List<Profile> profiles;
private Dictionary<string, string> settings;
private Dictionary<string, string> userSettings;
private string category = string.Empty;
private string filter = "to";
private List<Notification> notifications;
private string notificationSummary = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync()
{
try
{
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_togglepassword = SharedLocalizer["ShowPassword"];
allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
if (PageState.User != null)
{
@ -308,6 +396,11 @@ else
email = PageState.User.Email;
displayname = PageState.User.DisplayName;
if (string.IsNullOrEmpty(email))
{
AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
}
// get user folder
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
if (folder != null)
@ -326,10 +419,14 @@ else
photo = null;
}
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
userSettings = PageState.User.Settings;
var sitesettings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_ImageFiles = SettingService.GetSetting(userSettings, "ImageFiles", Constants.ImageFiles);
_ImageFiles = (string.IsNullOrEmpty(_ImageFiles)) ? Constants.ImageFiles : _ImageFiles;
await LoadNotificationsAsync();
_initialized = true;
}
else
{
@ -351,7 +448,7 @@ else
private string GetProfileValue(string SettingName, string DefaultValue)
{
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
string value = SettingService.GetSetting(userSettings, SettingName, DefaultValue);
if (value.Contains("]"))
{
value = value.Substring(value.IndexOf("]") + 1);
@ -363,44 +460,54 @@ else
{
try
{
if (username != string.Empty && email != string.Empty && ValidateProfiles())
if (username != string.Empty && email != string.Empty)
{
if (_password == confirm)
{
var user = PageState.User;
user.Username = username;
user.Password = _password;
user.TwoFactorRequired = bool.Parse(twofactor);
user.Email = email;
user.DisplayName = (displayname == string.Empty ? username : displayname);
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
if (ValidateProfiles())
{
user.PhotoFileId = null;
}
if (user.PhotoFileId != null)
{
photofileid = user.PhotoFileId.Value;
photo = await FileService.GetFileAsync(photofileid);
}
else
{
photofileid = -1;
photo = null;
}
var user = PageState.User;
user.Username = username;
user.Password = _password;
user.TwoFactorRequired = bool.Parse(twofactor);
user.Email = email;
user.DisplayName = (displayname == string.Empty ? username : displayname);
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
{
user.PhotoFileId = null;
}
if (user.PhotoFileId != null)
{
photofileid = user.PhotoFileId.Value;
photo = await FileService.GetFileAsync(photofileid);
}
else
{
photofileid = -1;
photo = null;
}
user = await UserService.UpdateUserAsync(user);
if (user != null)
{
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
user = await UserService.UpdateUserAsync(user);
if (user != null)
{
await SettingService.UpdateUserSettingsAsync(userSettings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
StateHasChanged();
}
else
{
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
{
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
else // legacy behavior
{
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
StateHasChanged();
}
}
else
{
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
}
}
}
else
@ -422,40 +529,72 @@ else
}
}
private async Task Logout()
{
await logger.LogInformation("User Logout Everywhere For Username {Username}", PageState.User?.Username);
var url = NavigateUrl(""); // home page
if (PageState.Runtime == Shared.Runtime.Hybrid)
{
if (PageState.User != null)
{
// hybrid apps utilize an interactive logout
await UserService.LogoutUserEverywhereAsync(PageState.User);
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(url, true);
}
}
else
{
// post to the Logout page to complete the logout process
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url, everywhere = true };
var interop = new Interop(jsRuntime);
await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields);
}
}
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
var value = GetProfileValue(profile.Name, string.Empty);
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
userSettings = SettingService.SetSetting(userSettings, profile.Name, profile.DefaultValue);
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
if (profile.IsRequired && string.IsNullOrEmpty(value))
{
valid = false;
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
return false;
}
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
if (!string.IsNullOrEmpty(profile.Validation))
{
Regex regex = new Regex(profile.Validation);
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
bool valid = regex.Match(value).Success;
if (!valid)
{
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
return false;
}
}
}
}
return valid;
return true;
}
private void Cancel()
{
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
userSettings = SettingService.SetSetting(userSettings, SettingName, value);
}
private async Task Delete(Notification Notification)
@ -486,7 +625,6 @@ else
private async void FilterChanged(ChangeEventArgs e)
{
filter = (string)e.Value;
await LoadNotificationsAsync();
StateHasChanged();
}
@ -495,7 +633,7 @@ else
{
try
{
ModuleInstance.ShowProgressIndicator();
ShowProgressIndicator();
foreach(var Notification in notifications)
{
if (!Notification.IsDeleted)
@ -508,34 +646,32 @@ else
await NotificationService.DeleteNotificationAsync(Notification.NotificationId);
}
await logger.LogInformation("Notification Deleted {Notification}", Notification);
}
}
await logger.LogInformation("Notifications Permanently Deleted");
await LoadNotificationsAsync();
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
StateHasChanged();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Notifications {Error}", ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
ModuleInstance.HideProgressIndicator();
HideProgressIndicator();
}
}
private void TogglePassword()
{
if (_passwordtype == "password")
{
_passwordtype = "text";
_togglepassword = SharedLocalizer["HidePassword"];
}
else
{
_passwordtype = "password";
_togglepassword = SharedLocalizer["ShowPassword"];
}
}
{
if (_passwordtype == "password")
{
_passwordtype = "text";
_togglepassword = SharedLocalizer["HidePassword"];
}
else
{
_passwordtype = "password";
_togglepassword = SharedLocalizer["ShowPassword"];
}
}
}

View File

@ -8,94 +8,71 @@
@if (PageState.User != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<label Class="col-sm-3">@Localizer["Title"] </label>
@if (title == "From")
{
<div class="col-sm-3">
<input class="form-control" @bind="@username" readonly />
</div>
}
@if (title == "To")
{
<div class="col-sm-3">
<input class="form-control" @bind="@username" />
</div>
}
</div>
<div class="row mb-1 align-items-center">
<label Class="col-sm-3">@Localizer["Subject"] </label>
@if (title == "From")
{
<div class="col-sm-3">
<input class="form-control" @bind="@subject" readonly />
</div>
}
@if (title == "To")
{
<div class="col-sm-3">
<input class="form-control" @bind="@subject" />
</div>
}
</div>
</div>
<div class="container">
@if (title == "From")
{
@if (title == "From")
{
<div class="container">
<div class="row mb-1 align-items-center">
<label class="col-sm-3">@Localizer["Date"] </label>
<Label Class="col-sm-3" For="username" HelpText="The user who sent the message" ResourceKey="From">From:</Label>
<div class="col-sm-9">
<input class="form-control" @bind="@createdon" readonly />
<input id="username" class="form-control" @bind="@username" readonly />
</div>
</div>
}
@if (title == "From")
{
<div class="row mb-1 align-items-center">
<label class="col-sm-3">@Localizer["Message"] </label>
<div class="col-sm-9">
<textarea id="txtFrom" class="form-control" @bind="@body" rows="5" readonly />
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="subject" HelpText="The subject of the message" ResourceKey="Subject">Subject:</Label>
<div class="col-sm-9">
<input id="subject" class="form-control" @bind="@subject" readonly />
</div>
}
@if (title == "To")
{
<div class="row mb-1 align-items-center">
<label class="col-sm-3">@Localizer["Message"] </label>
<div class="col-sm-9">
<textarea id="txtTo" class="form-control" @bind="@body" rows="5" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label class="col-sm-3" For="date" HelpText="The date the message was sent" ResourceKey="Date">Sent:</Label>
<div class="col-sm-9">
<input id="date" class="form-control" @bind="@createdon" readonly />
</div>
}
</div>
@if (reply != string.Empty)
{
<button type="button" class="btn btn-primary" @onclick="Send">@SharedLocalizer["Send"]</button>
</div>
<div class="row mb-1 align-items-center">
<Label class="col-sm-3" For="message" HelpText="The contents of the message" ResourceKey="Message">Message:</Label>
<div class="col-sm-9">
<textarea id="message" class="form-control" @bind="@body" rows="5" readonly />
</div>
</div>
</div>
}
else
{
if (title == "From")
{
<button type="button" class="btn btn-primary" @onclick="Reply">@Localizer["Reply"]</button>
}
}
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
@if (title == "To")
{
<div class="control-group">
<label class="control-label">@Localizer["OriginalMessage"] </label>
<textarea id="txtReply" class="form-control" @bind="@reply" rows="5" readonly />
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="username" HelpText="The user who will be the recipient of the message" ResourceKey="To">To:</Label>
<div class="col-sm-9">
<input id="username" class="form-control" @bind="@username" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="subject" HelpText="The subject of the message" ResourceKey="Subject">Subject:</Label>
<div class="col-sm-9">
<input id="subject" class="form-control" @bind="@subject" readonly="@(!reply)" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label class="col-sm-3" For="message" HelpText="The content of the message" ResourceKey="Message">Message:</Label>
<div class="col-sm-9">
<textarea id="message" class="form-control" @bind="@body" rows="5" readonly="@(!reply)" />
</div>
</div>
</div>
}
@if (reply)
{
<button type="button" class="btn btn-primary me-2" @onclick="Send">@SharedLocalizer["Send"]</button>
}
else
{
if (title == "From" && username != Localizer["System"])
{
<button type="button" class="btn btn-primary me-2" @onclick="Reply">@Localizer["Reply"]</button>
}
}
<NavLink class="btn btn-secondary" href="@PageState.ReturnUrl">@SharedLocalizer["Cancel"]</NavLink>
}
@code {
@ -105,7 +82,7 @@
private string subject = string.Empty;
private string createdon = string.Empty;
private string body = string.Empty;
private string reply = string.Empty;
private bool reply = false;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
public override string Title => "View Notification";
@ -118,9 +95,6 @@
Notification notification = await NotificationService.GetNotificationAsync(notificationid);
if (notification != null)
{
notification.IsRead = true;
notification = await NotificationService.UpdateNotificationAsync(notification);
int userid = -1;
if (notification.ToUserId == PageState.User.UserId)
{
@ -148,11 +122,17 @@
}
if (username == "")
{
username = "System";
username = Localizer["System"];
}
subject = notification.Subject;
createdon = notification.CreatedOn.ToString();
body = notification.Body;
if (title == "From" && !notification.IsRead)
{
notification.IsRead = true;
notification = await NotificationService.UpdateNotificationAsync(notification);
}
}
}
catch (Exception ex)
@ -165,12 +145,16 @@
private void Reply()
{
title = "To";
if (!subject.Contains("RE:"))
if (!subject.Contains(Localizer["RE:"]))
{
subject = "RE: " + subject;
subject = Localizer["RE"] + " " + subject;
}
reply = body;
body = "\n\n____________________________________________\nSent: " + createdon + "\nSubject: " + subject + "\n\n" + body;
body = $"\n\n____________________________________________\n" +
$"{Localizer["From.Text"]} {username}\n" +
$"{Localizer["Date.Text"]} {createdon}\n" +
$"{Localizer["Subject.Text"]} {subject}\n\n" +
body;
reply = true;
StateHasChanged();
}
@ -184,7 +168,7 @@
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, notificationid);
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
NavigationManager.NavigateTo(NavigateUrl());
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
else
{

View File

@ -8,63 +8,44 @@
@inject IStringLocalizer<Add> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
@if (profiles != null)
{
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
<div class="col-sm-9">
<input id="username" class="form-control" @bind="@_username" />
@if (_initialized)
{
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
@if (profiles != null)
{
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
<div class="col-sm-9">
<input id="username" class="form-control" @bind="@_username" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
<div class="col-sm-9">
<input id="email" class="form-control" @bind="@_email" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
<div class="col-sm-9">
<input id="displayname" class="form-control" @bind="@_displayname" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
<div class="col-sm-9">
<select id="notify" class="form-select" @bind="@_notify" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
<div class="col-sm-9">
<input id="email" class="form-control" @bind="@_email" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
<div class="col-sm-9">
<input id="displayname" class="form-control" @bind="@_displayname" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
<div class="col-sm-9">
<select id="notify" class="form-select" @bind="@_notify" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
@if (profiles != null)
{
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
<div class="container">
<div class="row mb-1 align-items-center">
@foreach (Profile profile in profiles)
@ -79,36 +60,51 @@
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
<div class="col-sm-9">
@if (p.IsRequired)
<div class="col-sm-9">
@if (!string.IsNullOrEmpty(p.Options))
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
{
<option value="@option" selected>@option</option>
}
else
{
<option value="@option">@option</option>
}
}
</select>
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
@if (p.Rows == 1)
{
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
else
{
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
}
</div>
</div>
}
</div>
</div>
}
</TabPanel>
</TabStrip>
<br />
<br />
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
</TabPanel>
</TabStrip>
<br />
<br />
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
}
@code {
private string _passwordrequirements;
private bool _initialized = false;
private string _username = string.Empty;
private string _password = string.Empty;
private string _passwordtype = "password";
private string _togglepassword = string.Empty;
private string _confirm = string.Empty;
private string _email = string.Empty;
private string _displayname = string.Empty;
private string _notify = "True";
@ -122,10 +118,9 @@
{
try
{
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_togglepassword = SharedLocalizer["ShowPassword"];
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
settings = new Dictionary<string, string>();
_initialized = true;
}
catch (Exception ex)
{
@ -148,14 +143,14 @@
{
try
{
if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty && _email != string.Empty && ValidateProfiles())
if (_username != string.Empty && _email != string.Empty)
{
if (_password == _confirm)
if (ValidateProfiles())
{
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = _username;
user.Password = _password;
user.Password = ""; // will be auto generated
user.Email = _email;
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
user.PhotoFileId = null;
@ -175,10 +170,6 @@
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
}
}
else
{
AddModuleMessage(Localizer["Message.Password.NoMatch"], MessageType.Warning);
}
}
else
{
@ -194,27 +185,33 @@
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
var value = GetProfileValue(profile.Name, string.Empty);
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
if (profile.IsRequired && string.IsNullOrEmpty(value))
{
valid = false;
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
return false;
}
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
if (!string.IsNullOrEmpty(profile.Validation))
{
Regex regex = new Regex(profile.Validation);
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
bool valid = regex.Match(value).Success;
if (!valid)
{
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
return false;
}
}
}
}
return valid;
return true;
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
@ -222,18 +219,4 @@
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
}
private void TogglePassword()
{
if (_passwordtype == "password")
{
_passwordtype = "text";
_togglepassword = SharedLocalizer["HidePassword"];
}
else
{
_passwordtype = "password";
_togglepassword = SharedLocalizer["ShowPassword"];
}
}
}

View File

@ -6,21 +6,14 @@
@inject IProfileService ProfileService
@inject ISettingService SettingService
@inject IFileService FileService
@inject IServiceProvider ServiceProvider
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@if (PageState.User != null && photo != null)
@if (_initialized)
{
<img src="@photo.Url" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
}
else
{
<br />
}
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
@if (profiles != null)
{
<TabStrip>
<TabPanel Name="Identity" ResourceKey="Identity">
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
<div class="container">
<div class="row mb-1 align-items-center">
@ -31,20 +24,20 @@ else
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<div class="input-group">
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
@ -59,21 +52,18 @@ else
<input id="displayname" class="form-control" @bind="@displayname" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="@photofileid.ToString()" HelpText="A photo of the user" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" @ref="filemanager" />
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="lastlogin" HelpText="The date and time when the user last signed in" ResourceKey="LastLogin"></Label>
<div class="col-sm-9">
@ -87,11 +77,8 @@ else
</div>
</div>
</div>
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
@if (profiles != null)
{
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
<div class="container">
<div class="row mb-1 align-items-center">
@foreach (Profile profile in profiles)
@ -125,13 +112,13 @@ else
}
else
{
@if (p.IsRequired)
@if (p.Rows == 1)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
}
}
</div>
@ -139,17 +126,25 @@ else
}
</div>
</div>
}
</TabPanel>
</TabStrip>
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin) && PageState.Runtime != Shared.Runtime.Hybrid && !ishost)
{
<button type="button" class="btn btn-primary ms-1" @onclick="ImpersonateUser">@Localizer["Impersonate"]</button>
}
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && isdeleted == "True")
{
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
}
<br /><br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code {
private bool _initialized = false;
private string _passwordrequirements;
private int userid;
private string username = string.Empty;
@ -159,15 +154,13 @@ else
private string confirm = string.Empty;
private string email = string.Empty;
private string displayname = string.Empty;
private FileManager filemanager;
private int photofileid = -1;
private File photo = null;
private string isdeleted;
private string lastlogin;
private string lastipaddress;
private bool ishost = false;
private List<Profile> profiles;
private Dictionary<string, string> settings;
private Dictionary<string, string> userSettings;
private string category = string.Empty;
private string createdby;
@ -179,37 +172,29 @@ else
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync()
{
try
{
if (PageState.QueryString.ContainsKey("id"))
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_togglepassword = SharedLocalizer["ShowPassword"];
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
{
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
_togglepassword = SharedLocalizer["ShowPassword"];
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
userid = Int32.Parse(PageState.QueryString["id"]);
userid = UserId;
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
if (user != null)
{
username = user.Username;
email = user.Email;
displayname = user.DisplayName;
if (user.PhotoFileId != null)
{
photofileid = user.PhotoFileId.Value;
photo = await FileService.GetFileAsync(photofileid);
}
else
{
photofileid = -1;
photo = null;
}
isdeleted = user.IsDeleted.ToString();
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
lastipaddress = user.LastIPAddress;
ishost = UserSecurity.ContainsRole(user.Roles, RoleNames.Host);
settings = await SettingService.GetUserSettingsAsync(user.UserId);
userSettings = user.Settings;
createdby = user.CreatedBy;
createdon = user.CreatedOn;
modifiedby = user.ModifiedBy;
@ -218,6 +203,8 @@ else
deletedon = user.DeletedOn;
}
}
_initialized = true;
}
catch (Exception ex)
{
@ -228,7 +215,7 @@ else
private string GetProfileValue(string SettingName, string DefaultValue)
{
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
string value = SettingService.GetSetting(userSettings, SettingName, DefaultValue);
if (value.Contains("]"))
{
value = value.Substring(value.IndexOf("]") + 1);
@ -240,35 +227,34 @@ else
{
try
{
if (username != string.Empty && email != string.Empty && ValidateProfiles())
if (username != string.Empty && email != string.Empty)
{
if (_password == confirm)
{
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = _password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null;
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
if (ValidateProfiles())
{
user.PhotoFileId = null;
}
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = _password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
}
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
user = await UserService.UpdateUserAsync(user);
if (user != null)
{
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
await logger.LogInformation("User Saved {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
user = await UserService.UpdateUserAsync(user);
if (user != null)
{
await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId);
await logger.LogInformation("User Saved {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
}
}
}
else
@ -288,35 +274,79 @@ else
}
}
private async Task ImpersonateUser()
{
try
{
await logger.LogInformation(LogFunction.Security, "User {Username} Impersonated By Administrator {Administrator}", username, PageState.User.Username);
// post back to the server so that the cookies are set correctly
var interop = new Interop(JSRuntime);
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = username, returnurl = PageState.Alias.Path };
string url = Utilities.TenantUrl(PageState.Alias, "/pages/impersonate/");
await interop.SubmitForm(url, fields);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Impersonating User {Username} {Error}", username, ex.Message);
AddModuleMessage(Localizer["Error.User.Impersonate"], MessageType.Error);
}
}
private async Task DeleteUser()
{
try
{
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && userid != PageState.User.UserId)
{
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
await logger.LogInformation("User Permanently Deleted {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Permanently Deleting User {UserId} {Error}", userid, ex.Message);
AddModuleMessage(Localizer["Error.DeleteUser"], MessageType.Error);
}
}
private bool ValidateProfiles()
{
bool valid = true;
foreach (Profile profile in profiles)
{
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
var value = GetProfileValue(profile.Name, string.Empty);
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
{
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
userSettings = SettingService.SetSetting(userSettings, profile.Name, profile.DefaultValue);
}
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
if (profile.IsRequired && string.IsNullOrEmpty(value))
{
valid = false;
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
return false;
}
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
if (!string.IsNullOrEmpty(profile.Validation))
{
Regex regex = new Regex(profile.Validation);
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
bool valid = regex.Match(value).Success;
if (!valid)
{
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
return false;
}
}
}
}
return valid;
return true;
}
private void ProfileChanged(ChangeEventArgs e, string SettingName)
{
var value = (string)e.Value;
settings = SettingService.SetSetting(settings, SettingName, value);
userSettings = SettingService.SetSetting(userSettings, SettingName, value);
}
private void TogglePassword()

File diff suppressed because it is too large Load Diff

View File

@ -34,13 +34,13 @@ else
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this role assignment is active" ResourceKey="EffectiveDate">Effective Date: </Label>
<div class="col-sm-9">
<input type="date" id="effectiveDate" class="form-control" @bind="@effectivedate" />
<input type="date" id="effectiveDate" class="form-control" @bind="@_effectivedate" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this role assignment expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
<div class="col-sm-9">
<input type="date" id="expiryDate" class="form-control" @bind="@expirydate" />
<input type="date" id="expiryDate" class="form-control" @bind="@_expirydate" />
</div>
</div>
@ -53,17 +53,17 @@ else
<p align="center">
<Pager Items="@userroles">
<Header>
<th>@Localizer["Roles"]</th>
<th>@Localizer["Effective"]</th>
<th>@Localizer["Expiry"]</th>
<th>&nbsp;</th>
<th>@Localizer["Roles"]</th>
<th>@Localizer["Effective"]</th>
<th>@Localizer["Expiry"]</th>
<th>&nbsp;</th>
</Header>
<Row>
<td>@context.Role.Name</td>
<td>@context.EffectiveDate</td>
<td>@context.ExpiryDate</td>
<td>@Utilities.UtcAsLocalDate(context.EffectiveDate)</td>
<td>@Utilities.UtcAsLocalDate(context.ExpiryDate)</td>
<td>
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.Name == RoleNames.Host && userid == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
</td>
</Row>
</Pager>
@ -75,8 +75,8 @@ else
private string name = string.Empty;
private List<Role> roles;
private int roleid = -1;
private DateTime? effectivedate = null;
private DateTime? expirydate = null;
private DateTime? _effectivedate = null;
private DateTime? _expirydate = null;
private List<UserRole> userroles;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
@ -92,7 +92,7 @@ else
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true);
roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated);
roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated);
}
else
{
@ -113,6 +113,7 @@ else
try
{
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, userid);
}
catch (Exception ex)
{
@ -127,11 +128,16 @@ else
{
if (roleid != -1)
{
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
{
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
return;
}
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
if (userrole != null)
{
userrole.EffectiveDate = effectivedate;
userrole.ExpiryDate = expirydate;
userrole.EffectiveDate = _effectivedate;
userrole.ExpiryDate = _expirydate;
await UserRoleService.UpdateUserRoleAsync(userrole);
}
else
@ -139,15 +145,15 @@ else
userrole = new UserRole();
userrole.UserId = userid;
userrole.RoleId = roleid;
userrole.EffectiveDate = effectivedate;
userrole.ExpiryDate = expirydate;
userrole.EffectiveDate = Utilities.UtcAsLocalDate(_effectivedate);
userrole.ExpiryDate = Utilities.UtcAsLocalDate(_expirydate);
await UserRoleService.AddUserRoleAsync(userrole);
}
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
AddModuleMessage(Localizer["Success.User.AssignRole"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
StateHasChanged();
}
else
{
@ -165,8 +171,18 @@ else
{
try
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId);
var userrole = await UserRoleService.GetUserRoleAsync(UserRoleId);
if (userrole.Role.Name == RoleNames.Registered)
{
userrole.ExpiryDate = DateTime.UtcNow;
await UserRoleService.UpdateUserRoleAsync(userrole);
await logger.LogInformation("User {Username} Expired From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
else
{
await UserRoleService.DeleteUserRoleAsync(UserRoleId);
await logger.LogInformation("User {Username} Removed From Role {Role}", userrole.User.Username, userrole.Role.Name);
}
AddModuleMessage(Localizer["Success.User.Remove"], MessageType.Success);
await GetUserRoles();
StateHasChanged();

View File

@ -43,7 +43,7 @@ else
<th>@Localizer["Created"]</th>
</Header>
<Row>
<td><ActionLink Action="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
<td><ActionLink Action="Detail" Text="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
<td>@context.IPAddress</td>
<td>
@if (context.UserId != null)
@ -69,16 +69,22 @@ else
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="duration" HelpText="The duration of a browsing session considered to be a distinct visit (in minutes)" ResourceKey="Duration">Session Duration: </Label>
<div class="col-sm-9">
<input id="duration" class="form-control" type="number" min="0" step="1" @bind="@_duration" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked" ResourceKey="Filter">Filter: </Label>
<div class="col-sm-9">
<textarea id="filter" class="form-control" @bind="@_filter" rows="3"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention (Days): </Label>
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention: </Label>
<div class="col-sm-9">
<input id="retention" class="form-control" @bind="@_retention" />
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
</div>
</div>
<div class="row mb-1 align-items-center">
@ -103,8 +109,9 @@ else
private int _page = 1;
private List<Visitor> _visitors;
private string _tracking;
private string _filter = "";
private string _retention = "";
private int _duration = 5;
private string _filter = "";
private int _retention = 30;
private string _correlation = "true";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
@ -128,8 +135,9 @@ else
_tracking = PageState.Site.VisitorTracking.ToString();
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
_retention = SettingService.GetSetting(settings, "VisitorRetention", "30");
_duration = int.Parse(SettingService.GetSetting(settings, "VisitorDuration", "5"));
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
}
@ -179,8 +187,9 @@ else
await SiteService.UpdateSiteAsync(site);
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention, true);
settings = SettingService.SetSetting(settings, "VisitorDuration", _duration.ToString(), true);
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);

View File

@ -2,50 +2,107 @@
@using System.Text.Json
@inherits LocalizableComponent
@inject IStringLocalizer<SharedResources> SharedLocalizer
@inject NavigationManager NavigationManager
@if (_visible)
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Header</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="DisplayModal"></button>
</div>
<div class="modal-body">
<p>@Message</p>
</div>
<div class="modal-footer">
@if (!string.IsNullOrEmpty(Action))
{
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
}
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@SharedLocalizer["Cancel"]</button>
@if (_visible)
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Header</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="DisplayModal"></button>
</div>
<div class="modal-body">
<p>@Message</p>
</div>
<div class="modal-footer">
@if (!string.IsNullOrEmpty(Action))
{
<button type="button" class="@ConfirmClass" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
}
<button type="button" class="@CancelClass" @onclick="DisplayModal">@SharedLocalizer["Cancel"]</button>
</div>
</div>
</div>
</div>
</div>
</div>
}
@if (_authorized)
{
if (Disabled)
{
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
}
else
@if (_authorized)
{
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
if (Disabled)
{
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
}
else
{
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_openIconSpan) @_openText</button>
}
}
}
else
{
@if (_visible)
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<form class="app-form-inline" method="post" @formname="@($"ActionDialogCloseForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<div class="modal-header">
<h5 class="modal-title">@Header</h5>
<button type="submit" class="btn-close" aria-label="Close"></button>
</div>
</form>
<div class="modal-body">
<p>@Message</p>
</div>
<div class="modal-footer">
@if (!string.IsNullOrEmpty(Action))
{
<form method="post" @formname="@($"ActionDialogConfirmForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="Confirm" data-enhance>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="@ConfirmClass">@((MarkupString)_iconSpan) @Text</button>
</form>
}
<form method="post" @formname="@($"ActionDialogCancelForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="@CancelClass">@SharedLocalizer["Cancel"]</button>
</form>
</div>
</div>
</div>
</div>
</div>
}
@if (_authorized)
{
if (Disabled)
{
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
}
else
{
<form method="post" class="app-form-inline" @formname="@($"ActionDialogActionForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="@Class">@((MarkupString)_openIconSpan) @_openText</button>
</form>
}
}
}
@code {
private bool _visible = false;
private List<Permission> _permissions;
private List<Permission> _permissions;
private bool _editmode = false;
private bool _authorized = false;
private string _iconSpan = string.Empty;
private string _openIconSpan = string.Empty;
private string _openText = string.Empty;
[Parameter]
public string Header { get; set; } // required
@ -62,15 +119,21 @@
[Parameter]
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
[Parameter]
public string Permissions { get; set; } // deprecated - use PermissionList instead
[Parameter]
public string Permissions { get; set; } // deprecated - use PermissionList instead
[Parameter]
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
[Parameter]
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
[Parameter]
public string Class { get; set; } // optional
[Parameter]
public string ConfirmClass { get; set; } // optional - for Confirm modal button
[Parameter]
public string CancelClass { get; set; } // optional - for Cancel modal button
[Parameter]
public bool Disabled { get; set; } // optional
@ -83,15 +146,21 @@
[Parameter]
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
protected override void OnInitialized()
{
if (!string.IsNullOrEmpty(Permissions))
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
protected override void OnParametersSet()
[Parameter]
public bool IconOnly { get; set; } // optional - specifies only icon in opening link
[Parameter]
public string Id { get; set; } // optional - specifies a unique id for the compoment - required when there are multiple component instances on a page in static rendering
protected override void OnInitialized()
{
if (!string.IsNullOrEmpty(Permissions))
{
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
}
}
protected override void OnParametersSet()
{
base.OnParametersSet();
@ -99,31 +168,60 @@
{
Text = Action;
}
if (string.IsNullOrEmpty(Class))
{
Class = "btn btn-success";
}
if (string.IsNullOrEmpty(ConfirmClass))
{
ConfirmClass = Class;
}
if (string.IsNullOrEmpty(CancelClass))
{
CancelClass = "btn btn-secondary";
}
if (!string.IsNullOrEmpty(EditMode))
{
_editmode = bool.Parse(EditMode);
}
if (!string.IsNullOrEmpty(IconName))
{
if (!IconName.Contains(" "))
{
IconName = "oi oi-" + IconName;
}
_iconSpan = $"<span class=\"{IconName}\"></span>&nbsp;";
}
Text = Localize(nameof(Text), Text);
Header = Localize(nameof(Header), Header);
Message = Localize(nameof(Message), Message);
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
_openText = Text;
if (!string.IsNullOrEmpty(IconName))
{
if (IconOnly)
{
_openText = string.Empty;
}
// Check if IconName starts with "oi oi-"
bool startsWithOiOi = IconName.StartsWith("oi oi-");
if (!startsWithOiOi && !IconName.Contains(" "))
{
IconName = "oi oi-" + IconName;
}
_openIconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : "&nbsp")}";
_iconSpan = $"<span class=\"{IconName}\"></span>&nbsp";
}
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
_authorized = IsAuthorized();
if (string.IsNullOrEmpty(Id)) Id = "1";
if (PageState.QueryString.ContainsKey("dialog"))
{
_visible = (PageState.QueryString["dialog"] == Id);
}
}
private bool IsAuthorized()
@ -175,12 +273,22 @@
private void DisplayModal()
{
_visible = !_visible;
StateHasChanged();
if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
{
StateHasChanged();
}
else
{
var parameters = new Dictionary<string, string>(PageState.QueryString);
if (parameters.ContainsKey("dialog")) parameters.Remove("dialog");
if (_visible) parameters.Add("dialog", Id);
NavigationManager.NavigateTo(PageState.Route.AbsolutePath + Utilities.CreateQueryString(parameters));
}
}
private void Confirm()
{
DisplayModal();
OnClick();
DisplayModal();
}
}

View File

@ -8,7 +8,7 @@
{
if (Disabled)
{
<button type="button" class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
<NavLink class="@($"{_classname} disabled")" href="@_url" style="@_style">@((MarkupString)_iconSpan) @_text</NavLink>
}
else
{
@ -97,10 +97,13 @@
{
base.OnParametersSet();
_text = Action;
if (!string.IsNullOrEmpty(Text))
{
_text = Text;
_text = Localize(nameof(Text), Text);
}
else
{
_text = Localize(nameof(Action), Action);
}
if (IconOnly && !string.IsNullOrEmpty(IconName))
@ -142,7 +145,10 @@
if (!string.IsNullOrEmpty(IconName))
{
if (!IconName.Contains(" "))
// Check if IconName starts with "oi oi-"
bool startsWithOiOi = IconName.StartsWith("oi oi-");
if (!startsWithOiOi && !IconName.Contains(" "))
{
IconName = "oi oi-" + IconName;
}
@ -150,7 +156,6 @@
}
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
_text = Localize(nameof(Text), _text);
_url = EditUrl(_path, _moduleId, Action, _parameters);
if (!string.IsNullOrEmpty(ReturnUrl))

View File

@ -3,6 +3,8 @@
@inherits ModuleControlBase
@inject IFolderService FolderService
@inject IFileService FileService
@inject IUserService UserService
@inject ISettingService SettingService
@inject IStringLocalizer<FileManager> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -40,10 +42,17 @@
</div>
</div>
}
else
{
if (FileId != -1 && _file != null && !UploadMultiple)
{
<input class="form-control" @bind="@_file.Name" disabled />
}
}
@if (ShowUpload && _haseditpermission)
{
<div class="row">
<div class="col mt-2">
<div class="row mt-2">
<div class="col">
@if (UploadMultiple)
{
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple />
@ -53,9 +62,9 @@
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
}
</div>
<div class="col mt-2 text-end">
<div class="col-auto">
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
@if (GetFileId() != -1)
@if (FileId != -1 && !UploadMultiple)
{
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
}
@ -76,6 +85,14 @@
}
}
}
@if (!string.IsNullOrEmpty(_message))
{
<div class="row mt-1">
<div class="col">
<ModuleMessage Message="@_message" Type="@_messagetype" />
</div>
</div>
}
</div>
</div>
@if (_image != string.Empty)
@ -85,14 +102,6 @@
</div>
}
</div>
@if (!string.IsNullOrEmpty(_message))
{
<div class="row mt-1">
<div class="col">
<ModuleMessage Message="@_message" Type="@_messagetype" />
</div>
</div>
}
</div>
}
@ -148,6 +157,9 @@
[Parameter]
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
[Parameter]
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
[Parameter]
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
@ -187,7 +199,7 @@
else
{
FolderId = -1;
_message = "Folder Path " + Folder + "Does Not Exist";
_message = "Folder Path " + Folder + " Does Not Exist";
_messagetype = MessageType.Error;
}
}
@ -217,9 +229,9 @@
}
else
{
FileId = -1; // file does not exist
_message = "FileId " + FileId.ToString() + "Does Not Exist";
_message = "FileId " + FileId.ToString() + " Does Not Exist";
_messagetype = MessageType.Error;
FileId = -1; // file does not exist
}
}
@ -305,7 +317,6 @@
await SetImage();
await OnSelect.InvokeAsync(FileId);
StateHasChanged();
}
private async Task SetImage()
@ -336,6 +347,7 @@
_message = string.Empty;
var interop = new Interop(JSRuntime);
var uploads = await interop.GetFiles(_fileinputid);
if (uploads.Length > 0)
{
string restricted = "";
@ -343,65 +355,49 @@
{
var filename = upload.Split(':')[0];
var extension = (filename.LastIndexOf(".") != -1) ? filename.Substring(filename.LastIndexOf(".") + 1) : "";
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
if (!PageState.Site.UploadableFiles.Split(',').Contains(extension.ToLower()))
{
restricted += (restricted == "" ? "" : ",") + extension;
}
}
if (restricted == "")
{
if (!ShowProgress)
{
_uploading = true;
StateHasChanged();
}
CancellationTokenSource tokenSource = new CancellationTokenSource();
try
{
// upload the files
var posturl = Utilities.TenantUrl(PageState.Alias, "/api/file/upload");
var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString();
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken);
// uploading is asynchronous so we need to poll to determine if uploads are completed
var success = true;
int upload = 0;
while (upload < uploads.Length && success)
var jwt = "";
if (PageState.Runtime == Shared.Runtime.Hybrid)
{
success = false;
var filename = uploads[upload].Split(':')[0];
var size = Int64.Parse(uploads[upload].Split(':')[1]);
var maxattempts = (int)Math.Ceiling(size / 500000.0) + 1; // 30 MB takes 1 minute at 5 Mbps
int attempts = 0;
while (attempts < maxattempts && !success)
jwt = await UserService.GetTokenAsync();
if (string.IsNullOrEmpty(jwt))
{
attempts += 1;
Thread.Sleep(1000);
if (Folder == Constants.PackagesFolder)
{
var files = await FileService.GetFilesAsync(folder);
if (files != null && files.Any(item => item.Name == filename))
{
success = true;
}
}
else
{
var file = await FileService.GetFileAsync(int.Parse(folder), filename);
if (file != null)
{
success = true;
}
}
}
if (success)
{
upload++;
await logger.LogInformation("File Upload Failed From .NET MAUI Due To Missing Security Token. Token Options Must Be Set In User Settings.");
_message = "Security Token Not Specified";
_messagetype = MessageType.Error;
return;
}
}
var chunksize = ChunkSize;
if (chunksize == 1)
{
// if ChunkSize parameter is not overridden use the site setting
chunksize = int.Parse(SettingService.GetSetting(PageState.Site.Settings, "MaxChunkSize", "1"));
}
if (!ShowProgress)
{
_uploading = true;
StateHasChanged();
}
// upload files
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, tokenSource.Token);
// reset progress indicators
if (ShowProgress)
{
@ -425,7 +421,7 @@
}
else
{
await logger.LogInformation("File Upload Failed Or Is Still In Progress {Files}", uploads);
await logger.LogError("File Upload Failed {Files}", uploads);
_message = Localizer["Error.File.Upload"];
_messagetype = MessageType.Error;
}
@ -455,6 +451,10 @@
_message = Localizer["Error.File.Upload"];
_messagetype = MessageType.Error;
_uploading = false;
await tokenSource.CancelAsync();
}
finally {
tokenSource.Dispose();
}
}

View File

@ -38,13 +38,10 @@
protected void OnChange(ChangeEventArgs e)
{
if (!string.IsNullOrEmpty(e.Value.ToString()))
Value = e.Value.ToString();
if (ValueChanged.HasDelegate)
{
Value = e.Value.ToString();
if (ValueChanged.HasDelegate)
{
ValueChanged.InvokeAsync(Value);
}
ValueChanged.InvokeAsync(Value);
}
}
}

View File

@ -2,15 +2,25 @@
@inherits ModuleControlBase
@inject NavigationManager NavigationManager
@if (!string.IsNullOrEmpty(_message))
@if (!string.IsNullOrEmpty(Message))
{
<div class="@_classname alert-dismissible fade show mb-3" role="alert">
@((MarkupString)_message)
@((MarkupString)Message)
@if (Type == MessageType.Error && PageState != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
@((MarkupString)"&nbsp;&nbsp;")<NavLink href="@NavigateUrl("admin/log")">View Details</NavLink>
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
}
@if (ModuleState != null)
{
@if (ModuleState.RenderMode == RenderModes.Static)
{
<a href="@NavigationManager.Uri" class="btn-close" data-dismiss="alert" aria-label="close"></a>
}
else
{
<button type="button" class="btn-close" data-dismiss="alert" aria-label="close" @onclick="CloseMessage"></button>
}
}
<button type="button" class="btn-close" aria-label="Close" @onclick="DismissModal"></button>
</div>
}
@ -24,6 +34,9 @@
[Parameter]
public MessageType Type { get; set; }
[Parameter]
public RenderModeBoundary Parent { get; set; }
protected override void OnParametersSet()
{
_message = Message;
@ -54,10 +67,15 @@
return classname;
}
private void DismissModal()
private void CloseMessage(MouseEventArgs e)
{
_message = "";
StateHasChanged();
if(Parent != null)
{
Parent.DismissMessage();
}
else
{
NavigationManager.NavigateTo(NavigationManager.Uri);
}
}
}

View File

@ -1,58 +1,137 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@inject IStringLocalizerFactory LocalizerFactory
@inject IStringLocalizer<SharedResources> SharedLocalizer
@typeparam TableItem
@if (ItemList != null)
{
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
{
<ul class="pagination justify-content-center my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
@if (!string.IsNullOrEmpty(SearchProperties))
{
<form autocomplete="off">
<div class="input-group my-3 @SearchBoxClass">
<input type="text" id="pagersearch" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
</div>
</form>
}
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
{
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
var pager = i;
if (pager == _page)
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item app-pager-pointer active">
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
</li>
}
else
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
<li class="page-item app-pager-pointer">
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
var pager = i;
if (pager == _page)
{
<li class="page-item app-pager-pointer active">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
</li>
}
else
{
<li class="page-item app-pager-pointer">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
<li class="page-item disabled">
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
<li class="page-item disabled">
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
}
}
else
{
@if (!string.IsNullOrEmpty(SearchProperties))
{
<form method="post" autocomplete="off" @formname="PagerForm" @onsubmit="Search" data-enhance>
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<div class="input-group my-3 @SearchBoxClass">
<input type="text" id="pagersearch" name="_search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
<button type="submit" class="btn btn-primary">@SharedLocalizer["Search"]</button>
<a class="btn btn-secondary" href="@PageUrl(1, "")">@SharedLocalizer["Reset"]</a>
</div>
</form>
}
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
{
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
var pager = i;
if (pager == _page)
{
<li class="page-item app-pager-pointer active">
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
</li>
}
else
{
<li class="page-item app-pager-pointer">
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
<li class="page-item disabled">
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
}
}
@if (Format == "Table" && Row != null)
{
<div class="table-responsive">
@ -116,53 +195,106 @@
}
</div>
}
@if ((Toolbar == "Bottom" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
{
<ul class="pagination justify-content-center my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
{
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
var pager = i;
if (pager == _page)
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item app-pager-pointer active">
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
</li>
}
else
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
<li class="page-item app-pager-pointer">
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
var pager = i;
if (pager == _page)
{
<li class="page-item app-pager-pointer active">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
</li>
}
else
{
<li class="page-item app-pager-pointer">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
<li class="page-item disabled">
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
<li class="page-item disabled">
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
}
else
{
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
</li>
@for (int i = _startPage; i <= _endPage; i++)
{
var pager = i;
if (pager == _page)
{
<li class="page-item app-pager-pointer active">
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
</li>
}
else
{
<li class="page-item app-pager-pointer">
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
</li>
}
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
</li>
@if (_pages > _displayPages && _displayPages > 1)
{
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
</li>
}
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
</li>
<li class="page-item disabled">
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
</li>
</ul>
}
}
}
@ -175,6 +307,9 @@
private int _startPage = 0;
private int _endPage = 0;
private int _columns = 0;
private string _search = "";
private IEnumerable<TableItem> AllItems;
[Parameter]
public string Format { get; set; } // Table or Grid
@ -221,6 +356,24 @@
[Parameter]
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
[Parameter]
public string SearchProperties { get; set; } // comma delimited list of property names to include in search
[Parameter]
public string SearchBoxClass { get; set; } // class for Search box
[Parameter]
public string Parameters { get; set; } // optional - querystring parameters in the form of "id=x&name=y" used in static render mode
[SupplyParameterFromForm(FormName = "PagerForm")]
public string _Search { get => ""; set => _search = value; }
/// <summary>
/// Accepted values are Start or Center or End. The default value is Center
/// </summary>
[Parameter]
public string PaginationAlignment { get; set; } = "center"; // Alignment of the Page Numbering start, center, end
private IEnumerable<TableItem> ItemList { get; set; }
protected override void OnInitialized()
@ -276,6 +429,20 @@
}
}
if (PageState.QueryString.ContainsKey("search"))
{
_search = PageState.QueryString["search"];
}
if (!string.IsNullOrEmpty(SearchProperties))
{
AllItems = Items; // only used in search
if (!string.IsNullOrEmpty(_search))
{
Search();
}
}
if (!string.IsNullOrEmpty(PageSize))
{
_maxItems = int.Parse(PageSize);
@ -291,13 +458,20 @@
_displayPages = int.Parse(DisplayPages);
}
if (!string.IsNullOrEmpty(CurrentPage))
if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page))
{
_page = int.Parse(CurrentPage);
_page = page;
}
else
{
_page = 1;
if (!string.IsNullOrEmpty(CurrentPage))
{
_page = int.Parse(CurrentPage);
}
else
{
_page = 1;
}
}
if (_page < 1) _page = 1;
@ -323,10 +497,10 @@
{
_endPage = _pages;
}
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
StateHasChanged();
OnPageChange?.Invoke(_page);
}
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
StateHasChanged();
OnPageChange?.Invoke(_page);
}
public void UpdateList(int page)
{
@ -369,4 +543,96 @@
UpdateList(_page);
}
public void Search()
{
if (!string.IsNullOrEmpty(_search))
{
Items = AllItems.Where(item =>
{
var values = SearchProperties.Split(',')
.Select(itemType => GetPropertyValue(item, itemType))
.Where(value => value != null)
.Select(value => value.ToString().ToLower());
return values.Any(value => value.Contains(_search.ToLower()));
}).ToList();
}
else
{
Items = AllItems;
}
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
UpdateList(1);
}
private object GetPropertyValue(object obj, string propertyName)
{
var index = propertyName.IndexOf(".");
if (index != -1)
{
var propertyInfo = obj.GetType().GetProperty(propertyName.Substring(0, index));
if (propertyInfo != null)
{
return GetPropertyValue(propertyInfo.GetValue(obj), propertyName.Substring(index + 1));
}
return null;
}
else
{
var propertyInfo = obj.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
return propertyInfo.GetValue(obj);
}
return null;
}
}
public void Reset()
{
_search = "";
Items = AllItems;
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
UpdateList(1);
}
private string FormatSearchProperties()
{
var properties = new List<string>();
foreach (var property in SearchProperties.Split(',', StringSplitOptions.RemoveEmptyEntries))
{
var index = property.LastIndexOf(".");
if (index != -1)
{
properties.Add(property.Substring(index + 1));
}
else
{
properties.Add(property);
}
}
return string.Join(",", properties);
}
private string PageUrl(int page, string search)
{
var parameters = new Dictionary<string, string>(PageState.QueryString);
if (parameters.ContainsKey("page")) parameters.Remove("page");
parameters.Add("page", page.ToString());
if (parameters.ContainsKey("search")) parameters.Remove("search");
if (!string.IsNullOrEmpty(search))
{
parameters.Add("search", search);
}
if (!string.IsNullOrEmpty(Parameters))
{
foreach (var parameter in Utilities.ParseQueryString(Parameters))
{
if (parameters.ContainsKey(parameter.Key)) parameters.Remove(parameter.Key);
parameters.Add(parameter.Key, parameter.Value);
}
}
return PageState.Route.AbsolutePath + Utilities.CreateQueryString(parameters);
}
}

View File

@ -111,7 +111,7 @@
[Parameter]
public List<Permission> PermissionList { get; set; }
protected override async Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
if (!string.IsNullOrEmpty(Permissions))
{

View File

@ -4,11 +4,11 @@ using System.Threading.Tasks;
namespace Oqtane.Modules.Controls
{
public class RichTextEditorInterop
public class QuillEditorInterop
{
private readonly IJSRuntime _jsRuntime;
public RichTextEditorInterop(IJSRuntime jsRuntime)
public QuillEditorInterop(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
@ -105,13 +105,25 @@ namespace Oqtane.Modules.Controls
}
}
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText)
public ValueTask<int> GetCurrentCursor(ElementReference quillElement)
{
try
{
return _jsRuntime.InvokeAsync<int>("Oqtane.RichTextEditor.getCurrentCursor", quillElement);
}
catch
{
return new ValueTask<int>(Task.FromResult(0));
}
}
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText, int editorIndex)
{
try
{
_jsRuntime.InvokeAsync<object>(
"Oqtane.RichTextEditor.insertQuillImage",
quillElement, imageUrl, altText);
quillElement, imageUrl, altText, editorIndex);
return Task.CompletedTask;
}
catch

View File

@ -0,0 +1,578 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@implements ITextEditor
@inject ISettingService SettingService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<QuillJSTextEditor> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<div class="quill-text-editor">
<TabStrip ActiveTab="@_activetab">
@if (_allowRichText)
{
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
@if (_richfilemanager)
{
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
<div class="d-flex justify-content-center mb-2">
@if (_allowFileManagement)
{
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
}
@if (_richfilemanager)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseRichFileManager">@Localizer["Close"]</button>
}
</div>
<div class="row">
<div class="col">
<div @ref="@_toolBar">
@if (!string.IsNullOrEmpty(_toolbarContent))
{
@((MarkupString)_toolbarContent)
}
else
{
<select class="ql-header">
<option selected=""></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
</select>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
</span>
}
</div>
<div @ref="@_editorElement"></div>
</div>
</div>
</TabPanel>
}
@if (_allowRawHtml)
{
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
@if (_rawfilemanager)
{
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
<div class="d-flex justify-content-center mb-2">
@if (_allowFileManagement)
{
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
}
@if (_rawfilemanager)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
}
</div>
@if (ReadOnly)
{
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
}
else
{
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
}
</TabPanel>
}
@if (_allowSettings)
{
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
<div class="quill-text-editor-settings">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="Scope" ResourceKey="Scope" ResourceType="@resourceType" HelpText="Specify if settings are scoped to the module or site">Scope: </Label>
<div class="col-sm-9">
<select id="Scope" class="form-select" value="@_scopeSetting" @onchange="(e => ScopeChanged(e))">
<option value="Module">@SharedLocalizer["Module"]</option>
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
<option value="Site">@SharedLocalizer["Site"]</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="AllowRichText" ResourceKey="AllowRichText" ResourceType="@resourceType" HelpText="Specify if editors can use the Rich Text Editor">Rich Text Editor? </Label>
<div class="col-sm-9">
<select id="AllowRichText" class="form-select" @bind="@_allowRichTextSetting" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="AllowRawHtml" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify if editors can use the Raw HTML Editor">Raw HTML Editor? </Label>
<div class="col-sm-9">
<select id="AllowRawHtml" class="form-select" @bind="@_allowRawHtmlSetting" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="AllowFileManagement" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify if editors can upload and insert images">Insert Images? </Label>
<div class="col-sm-9">
<select id="AllowFileManagement" class="form-select" @bind="@_allowFileManagementSetting" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="Theme" ResourceKey="Theme" ResourceType="@resourceType" HelpText="Specify the Rich Text Editor's theme">Theme: </Label>
<div class="col-sm-9">
<input type="text" id="Theme" class="form-control" @bind="_themeSetting" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="DebugLevel" ResourceKey="DebugLevel" ResourceType="@resourceType" HelpText="Specify the Debug Level">Debug Level: </Label>
<div class="col-sm-9">
<select id="DebugLevel" class="form-select" @bind="_debugLevelSetting">
@foreach (var level in _debugLevels)
{
<option value="@level">@level</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ToolbarContent" ResourceKey="ToolbarContent" ResourceType="@resourceType" HelpText="Specify any toolbar content to customize the Rich Text Editor">Toolbar Content: </Label>
<div class="col-sm-9">
<textarea id="ToolbarContent" class="form-control" @bind="_toolbarContentSetting" rows="3" />
</div>
</div>
<div class="row mb-1 align-items-center">
<div class="col-sm-9 offset-sm-3">
<button type="button" class="btn btn-success" @onclick="@(async () => await UpdateSettings())">@Localizer["SaveSettings"]</button>
</div>
</div>
</div>
</TabPanel>
}
</TabStrip>
</div>
@code {
public string Name => "QuillJS";
private string resourceType = "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
private bool _settingsLoaded;
private bool _initialized = false;
private QuillEditorInterop _interop;
private FileManager _fileManager;
private string _activetab = "Rich";
private bool _allowSettings = false;
private bool _allowFileManagement = false;
private bool _allowRawHtml = false;
private bool _allowRichText = false;
private string _theme = "snow";
private string _debugLevel = "info";
private string _toolbarContent = string.Empty;
private string _scopeSetting = "Module";
private string _allowFileManagementSetting = "False";
private string _allowRawHtmlSetting = "False";
private string _allowRichTextSetting = "False";
private string _themeSetting = "snow";
private string _debugLevelSetting = "info";
private string _toolbarContentSetting = string.Empty;
private ElementReference _editorElement;
private ElementReference _toolBar;
private bool _richfilemanager = false;
private string _richhtml = string.Empty;
private string _originalrichhtml = string.Empty;
private bool _rawfilemanager = false;
private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N");
private string _rawhtml = string.Empty;
private string _originalrawhtml = string.Empty;
private string _message = string.Empty;
private bool _contentchanged = false;
private int _editorIndex;
private List<string> _debugLevels = new List<string> { "info", "log", "warn", "error" };
[Parameter]
public bool ReadOnly { get; set; }
[Parameter]
public string Placeholder { get; set; }
// the following parameters were supported by the original RichTextEditor and can be passed as optional static parameters
[Parameter]
public bool? AllowFileManagement { get; set; }
[Parameter]
public bool? AllowRichText { get; set; }
[Parameter]
public bool? AllowRawHtml { get; set; }
[Parameter]
public string Theme { get; set; }
[Parameter]
public string DebugLevel { get; set; }
public override List<Resource> Resources { get; set; } = new List<Resource>()
{
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
};
protected override void OnInitialized()
{
_interop = new QuillEditorInterop(JSRuntime);
if (string.IsNullOrEmpty(Placeholder))
{
Placeholder = Localizer["Placeholder"];
}
}
protected override void OnParametersSet()
{
LoadSettings();
if (!_allowRichText)
{
_activetab = "Raw";
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// include CSS theme
var interop = new Interop(JSRuntime);
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/quill/quill.{_theme}.css", "text/css", "", "", "");
}
await base.OnAfterRenderAsync(firstRender);
if (_allowRichText)
{
if (firstRender)
{
await _interop.CreateEditor(
_editorElement,
_toolBar,
ReadOnly,
Placeholder,
_theme,
_debugLevel);
await _interop.LoadEditorContent(_editorElement, _richhtml);
// preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified)
_originalrichhtml = await _interop.GetHtml(_editorElement);
_initialized = true;
}
else
{
if (_initialized)
{
if (_contentchanged)
{
// reload editor if Content passed to component has changed
await _interop.LoadEditorContent(_editorElement, _richhtml);
_originalrichhtml = await _interop.GetHtml(_editorElement);
_contentchanged = false;
}
else
{
// preserve changed content on re-render event
var richhtml = await _interop.GetHtml(_editorElement);
if (richhtml != _richhtml)
{
_richhtml = richhtml;
await _interop.LoadEditorContent(_editorElement, _richhtml);
}
}
}
}
}
}
public void Initialize(string content)
{
_richhtml = content;
_rawhtml = content;
_originalrichhtml = "";
_richhtml = content;
if (!_contentchanged)
{
_contentchanged = content != _originalrawhtml;
}
_originalrawhtml = _rawhtml; // preserve for comparison later
StateHasChanged();
}
public async Task<string> GetContent()
{
// evaluate raw html content as first priority
if (_rawhtml != _originalrawhtml)
{
return _rawhtml;
}
else
{
var richhtml = "";
if (_allowRichText)
{
richhtml = await _interop.GetHtml(_editorElement);
}
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
{
// convert Quill's empty content to empty string
if (richhtml == "<p><br></p>")
{
richhtml = string.Empty;
}
return richhtml;
}
else
{
// return original raw html content
return _originalrawhtml;
}
}
}
public void CloseRichFileManager()
{
_richfilemanager = false;
_message = string.Empty;
StateHasChanged();
}
public void CloseRawFileManager()
{
_rawfilemanager = false;
_message = string.Empty;
StateHasChanged();
}
public async Task<string> GetHtml()
{
// evaluate raw html content as first priority
if (_rawhtml != _originalrawhtml)
{
return _rawhtml;
}
else
{
var richhtml = "";
if (_allowRichText)
{
richhtml = await _interop.GetHtml(_editorElement);
}
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
{
// convert Quill's empty content to empty string
if (richhtml == "<p><br></p>")
{
richhtml = string.Empty;
}
return richhtml;
}
else
{
// return original raw html content
return _originalrawhtml;
}
}
}
public async Task InsertRichImage()
{
_message = string.Empty;
if (_richfilemanager)
{
var file = _fileManager.GetFile();
if (file != null)
{
await _interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name), _editorIndex);
_richhtml = await _interop.GetHtml(_editorElement);
_richfilemanager = false;
}
else
{
_message = Localizer["Message.Require.Image"];
}
}
else
{
_editorIndex = await _interop.GetCurrentCursor(_editorElement);
_richfilemanager = true;
}
StateHasChanged();
}
public async Task InsertRawImage()
{
_message = string.Empty;
if (_rawfilemanager)
{
var file = _fileManager.GetFile();
if (file != null)
{
var interop = new Interop(JSRuntime);
int pos = await interop.GetCaretPosition(_rawhtmlid);
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
_rawfilemanager = false;
}
else
{
_message = Localizer["Message.Require.Image"];
}
}
else
{
_rawfilemanager = true;
}
StateHasChanged();
}
private void ScopeChanged(ChangeEventArgs e)
{
_scopeSetting = (string)e.Value;
LoadSettings();
}
private void LoadSettings(bool reload = false)
{
try
{
if (!_settingsLoaded || reload)
{
_allowFileManagement = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowFileManagement", "True"));
_allowRawHtml = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowRawHtml", "True"));
_allowRichText = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowRichText", "True"));
_theme = GetSetting("Component", "QuillTextEditor_Theme", "snow");
_debugLevel = GetSetting("Component", "QuillTextEditor_DebugLevel", "info");
_toolbarContent = GetSetting("Component", "QuillTextEditor_ToolbarContent", string.Empty);
// optional static parameter overrides
if (AllowFileManagement != null) _allowFileManagement = AllowFileManagement.Value;
if (AllowRichText != null) _allowRichText = AllowRichText.Value;
if (AllowRawHtml != null) _allowRawHtml = AllowRawHtml.Value;
if (!string.IsNullOrEmpty(Theme)) _theme = Theme;
if (!string.IsNullOrEmpty(DebugLevel)) _debugLevel = DebugLevel;
}
_allowSettings = PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList);
if (_allowSettings)
{
_allowFileManagementSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowFileManagement", "True");
_allowRawHtmlSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowRawHtml", "True");
_allowRichTextSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowRichText", "True");
_themeSetting = GetSetting(_scopeSetting, "QuillTextEditor_Theme", "snow");
_debugLevelSetting = GetSetting(_scopeSetting, "QuillTextEditor_DebugLevel", "info");
_toolbarContentSetting = GetSetting(_scopeSetting, "QuillTextEditor_ToolbarContent", string.Empty);
}
_settingsLoaded = true;
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
private string GetSetting(string scope, string settingName, string defaultValue)
{
var settingValue = "";
switch (scope)
{
case "Component":
settingValue = SettingService.GetSetting(PageState.Site.Settings, settingName, defaultValue);
settingValue = SettingService.GetSetting(ModuleState.Settings, settingName, settingValue);
break;
case "Site":
settingValue = SettingService.GetSetting(PageState.Site.Settings, settingName, defaultValue);
break;
case "Module":
settingValue = SettingService.GetSetting(ModuleState.Settings, settingName, defaultValue);
break;
}
return settingValue;
}
private async Task UpdateSettings()
{
try
{
if (_scopeSetting == "Site" && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowFileManagement", _allowFileManagementSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRawHtml", _allowRawHtmlSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRichText", _allowRichTextSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_Theme", _themeSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_DebugLevel", _debugLevelSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_ToolbarContent", _toolbarContentSetting);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
}
else if (_scopeSetting == "Module")
{
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowFileManagement", _allowFileManagementSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRawHtml", _allowRawHtmlSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRichText", _allowRichTextSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_Theme", _themeSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_DebugLevel", _debugLevelSetting);
settings = SettingService.SetSetting(settings, "QuillTextEditor_ToolbarContent", _toolbarContentSetting);
await SettingService.UpdateModuleSettingsAsync(settings,ModuleState.ModuleId);
}
LoadSettings(true);
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
catch (Exception ex)
{
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -1,280 +1,127 @@
@using System.Text.RegularExpressions
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.Extensions.DependencyInjection
@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@inject IServiceProvider ServiceProvider
@inject ISettingService SettingService
@inject IStringLocalizer<RichTextEditor> Localizer
<div class="row" style="margin-bottom: 50px;">
<div class="col">
<TabStrip>
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
@if (_richfilemanager)
{
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
<div class="d-flex justify-content-center mb-2">
@if (AllowRawHtml)
{
<button type="button" class="btn btn-secondary" @onclick="RefreshRichText">@Localizer["SynchronizeContent"]</button>@((MarkupString)"&nbsp;&nbsp;")
}
@if (AllowFileManagement)
{
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
}
@if (_richfilemanager)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseRichFileManager">@Localizer["Close"]</button>
}
</div>
<div class="row">
<div class="col">
<div @ref="@_toolBar">
@if (ToolbarContent != null)
{
@ToolbarContent
}
else
{
<select class="ql-header">
<option selected=""></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
</select>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
</span>
}
</div>
<div @ref="@_editorElement">
</div>
</div>
</div>
</TabPanel>
@if (AllowRawHtml)
{
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
@if (_rawfilemanager)
{
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
<div class="d-flex justify-content-center mb-2">
<button type="button" class="btn btn-secondary" @onclick="RefreshRawHtml">@Localizer["SynchronizeContent"]</button>&nbsp;&nbsp;
@if (AllowFileManagement)
{
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
}
@if (_rawfilemanager)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
}
</div>
@if (ReadOnly)
{
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
}
else
{
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
}
</TabPanel>
}
</TabStrip>
@_textEditorComponent
</div>
</div>
@code {
private ElementReference _editorElement;
private ElementReference _toolBar;
private bool _richfilemanager = false;
private FileManager _fileManager;
private string _richhtml = string.Empty;
private string _originalrichhtml = string.Empty;
private bool _rawfilemanager = false;
private string _rawhtml = string.Empty;
private string _originalrawhtml = string.Empty;
private string _message = string.Empty;
private string _textEditorType;
private RenderFragment _textEditorComponent;
private ITextEditor _textEditor;
[Parameter]
public string Content { get; set; }
[Parameter]
public string Content { get; set; }
[Parameter]
public bool ReadOnly { get; set; } = false;
[Parameter]
public bool ReadOnly { get; set; } = false;
[Parameter]
public string Placeholder { get; set; } = "Enter Your Content...";
[Parameter]
public string Placeholder { get; set; }
[Parameter]
public bool AllowFileManagement { get; set; } = true;
[Parameter]
public string Provider { get; set; }
[Parameter]
public bool AllowRawHtml { get; set; } = true;
// parameters only applicable to rich text editor
[Parameter]
public RenderFragment ToolbarContent { get; set; }
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>();
[Parameter]
public string Theme { get; set; } = "snow";
[Parameter]
public string DebugLevel { get; set; } = "info";
public override List<Resource> Resources => new List<Resource>()
protected override void OnInitialized()
{
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
};
_textEditorType = GetTextEditorType();
}
protected override void OnParametersSet()
{
_richhtml = Content;
_rawhtml = Content;
_originalrawhtml = _rawhtml; // preserve for comparison later
}
protected override void OnParametersSet()
{
_textEditorComponent = (builder) =>
{
CreateTextEditor(builder);
};
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(_textEditor != null)
{
_textEditor.Initialize(Content);
}
var interop = new RichTextEditorInterop(JSRuntime);
await base.OnAfterRenderAsync(firstRender);
}
if (firstRender)
{
await interop.CreateEditor(
_editorElement,
_toolBar,
ReadOnly,
Placeholder,
Theme,
DebugLevel);
public async Task<string> GetHtml()
{
return await _textEditor.GetContent();
}
await interop.LoadEditorContent(_editorElement, _richhtml);
private void CreateTextEditor(RenderTreeBuilder builder)
{
if(!string.IsNullOrEmpty(_textEditorType))
{
var editorType = Type.GetType(_textEditorType);
if (editorType != null)
{
builder.OpenComponent(0, editorType);
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
_originalrichhtml = await interop.GetHtml(_editorElement);
}
}
var attributes = new Dictionary<string, object>
{
{ "Placeholder", Placeholder },
{ "ReadOnly", ReadOnly }
};
public void CloseRichFileManager()
{
_richfilemanager = false;
_message = string.Empty;
StateHasChanged();
}
if (AdditionalAttributes != null)
{
foreach(var key in AdditionalAttributes.Keys)
{
if(!attributes.ContainsKey(key))
{
attributes.Add(key, AdditionalAttributes[key]);
}
else
{
attributes[key] = AdditionalAttributes[key];
}
}
}
public void CloseRawFileManager()
{
_rawfilemanager = false;
_message = string.Empty;
StateHasChanged();
}
var index = 1;
foreach(var name in attributes.Keys)
{
if (editorType.GetProperty(name) != null)
{
builder.AddAttribute(index++, name, attributes[name]);
}
}
public void RefreshRichText()
{
_richhtml = _rawhtml;
StateHasChanged();
}
builder.AddComponentReferenceCapture(index, (c) =>
{
_textEditor = (ITextEditor)c;
});
builder.CloseComponent();
}
}
}
public async Task RefreshRawHtml()
{
var interop = new RichTextEditorInterop(JSRuntime);
_rawhtml = await interop.GetHtml(_editorElement);
StateHasChanged();
}
private string GetTextEditorType()
{
const string EditorSettingName = "TextEditor";
public async Task<string> GetHtml()
{
// evaluate raw html content as first priority
if (_rawhtml != _originalrawhtml)
{
return _rawhtml;
}
else
{
// return rich text content if it has changed
var interop = new RichTextEditorInterop(JSRuntime);
var richhtml = await interop.GetHtml(_editorElement);
if (richhtml != _originalrichhtml)
{
return richhtml;
}
else
{
// return original raw html content
return _originalrawhtml;
}
}
}
if(!string.IsNullOrEmpty(Provider))
{
var provider = ServiceProvider.GetServices<ITextEditor>().FirstOrDefault(i => i.Name.Equals(Provider, StringComparison.OrdinalIgnoreCase));
if(provider != null)
{
return Utilities.GetFullTypeName(provider.GetType().AssemblyQualifiedName);
}
}
public async Task InsertRichImage()
{
_message = string.Empty;
if (_richfilemanager)
{
var file = _fileManager.GetFile();
if (file != null)
{
var interop = new RichTextEditorInterop(JSRuntime);
await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name));
_richfilemanager = false;
}
else
{
_message = Localizer["Message.Require.Image"];
}
}
else
{
_richfilemanager = true;
}
StateHasChanged();
}
public async Task InsertRawImage()
{
_message = string.Empty;
if (_rawfilemanager)
{
var file = _fileManager.GetFile();
if (file != null)
{
var interop = new Interop(JSRuntime);
int pos = await interop.GetCaretPosition("rawhtmleditor");
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
_rawfilemanager = false;
}
else
{
_message = Localizer["Message.Require.Image"];
}
}
else
{
_rawfilemanager = true;
}
StateHasChanged();
}
return SettingService.GetSetting(PageState.Site.Settings, EditorSettingName, Constants.DefaultTextEditor);
}
}

View File

@ -1,27 +1,30 @@
@namespace Oqtane.Modules.Controls
@inherits LocalizableComponent
<div class="d-flex mt-2">
<div>
<a data-bs-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<h5>@_heading</h5>
</a>
@if (IsVisible)
{
<div class="d-flex mt-2">
<div>
<a data-bs-toggle="collapse" class="app-link-unstyled" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<h5>@_heading</h5>
</a>
</div>
<div class="ms-auto">
<a data-bs-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<i class="oi oi-chevron-bottom"></i>&nbsp;
</a>
</div>
</div>
<div class="ms-auto">
<a data-bs-toggle="collapse" class="app-link-unstyled float-right" href="#@Name" aria-expanded="@_expanded" aria-controls="@Name" @onclick:preventDefault="true">
<i class="oi oi-chevron-bottom"></i>&nbsp;
</a>
<div class="d-flex">
<hr class="app-rule" />
</div>
</div>
<div class="d-flex">
<hr class="app-rule" />
</div>
<div class="collapse @_show" id="@Name">
@if (ChildContent != null)
{
@ChildContent
}
</div>
<div class="collapse @_show" id="@Name">
@if (ChildContent != null)
{
@ChildContent
}
</div>
}
@code {
private string _heading = string.Empty;
@ -40,6 +43,9 @@
[Parameter]
public string Expanded { get; set; } // optional - will default to false if not provided
[Parameter]
public bool IsVisible { get; set; } = true;
protected override void OnParametersSet()
{
base.OnParametersSet(); // must be included to call method in LocalizableComponent

View File

@ -36,14 +36,7 @@ else
Parent.AddTabPanel((TabPanel)this);
if (string.IsNullOrEmpty(Heading))
{
Heading = Localize(nameof(Name), Name);
}
else
{
Heading = Localize(nameof(Heading), Heading);
}
Heading = string.IsNullOrEmpty(Heading) ? Localize(nameof(Name), Name) : Localize(nameof(Heading), Heading);
}
public string DisplayHeading()

View File

@ -23,7 +23,7 @@
</li>
}
</ul>
<div class="tab-content">
<div class="tab-content @TabContentClass">
<br />
@ChildContent
</div>
@ -47,6 +47,9 @@
[Parameter]
public string Id { get; set; } // optional - used to uniquely identify an instance of a tab strip component (will be set automatically if no value provided)
[Parameter]
public string TabContentClass { get; set; } // optional - to extend the TabContent div.
protected override void OnInitialized()
{
if (string.IsNullOrEmpty(Id))

View File

@ -0,0 +1,33 @@
@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@implements ITextEditor
<div class="text-area-editor">
<textarea @bind="_content" @ref="_editor" placeholder="@Placeholder" readonly="@ReadOnly" />
</div>
@code {
public string Name => "TextArea";
private ElementReference _editor;
private string _content;
[Parameter]
public bool ReadOnly { get; set; }
[Parameter]
public string Placeholder { get; set; }
public void Initialize(string content)
{
_content = content;
StateHasChanged();
}
public async Task<string> GetContent()
{
await Task.CompletedTask;
return _content;
}
}

View File

@ -13,7 +13,7 @@
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
@if (_content != null)
{
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" AllowRawHtml="@_allowrawhtml" @ref="@RichTextEditorHtml"></RichTextEditor>
<RichTextEditor Content="@_content" @ref="@RichTextEditorHtml"></RichTextEditor>
<br />
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
@ -47,44 +47,34 @@
</TabStrip>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override string Title => "Edit Html/Text";
public override string Title => "Edit Html/Text";
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
};
private RichTextEditor RichTextEditorHtml;
private string _content = null;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private List<Models.HtmlText> _htmltexts;
private string _view = "";
private RichTextEditor RichTextEditorHtml;
private bool _allowfilemanagement;
private bool _allowrawhtml;
private string _content = null;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private List<Models.HtmlText> _htmltexts;
private string _view = "";
protected override async Task OnInitializedAsync()
{
try
{
await LoadContent();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
}
}
protected override async Task OnInitializedAsync()
{
try
{
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
_allowrawhtml = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true"));
await LoadContent();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
}
}
private async Task LoadContent()
{
private async Task LoadContent()
{
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{

View File

@ -2,30 +2,50 @@
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject IHtmlTextService HtmlTextService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@((MarkupString)content)
@if (PageState.EditMode)
{
<br />
<ActionLink Action="Edit" EditMode="true" ResourceKey="Edit" />
<br />
<br />
<div class="text-center mb-2">
<ActionLink Action="Edit" EditMode="true" ResourceKey="Edit" />
</div>
}
@((MarkupString)content)
@if (PageState.EditMode && content.Length > 3000)
{
<div class="text-center mt-2">
<ActionLink Action="Edit" EditMode="true" ResourceKey="Edit" />
</div>
}
@code {
private string content = "";
private string content = "";
protected override async Task OnParametersSetAsync()
{
try
public override string RenderMode => RenderModes.Static;
protected override async Task OnParametersSetAsync()
{
try
{
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
if (ShouldRender())
{
content = htmltext.Content;
content = Utilities.FormatContent(content, PageState.Alias, "render");
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{
content = htmltext.Content;
content = Utilities.FormatContent(content, PageState.Alias, "render");
if (bool.Parse(SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false")))
{
content = ReplaceTokens(content);
}
}
else
{
content = "";
}
}
}
catch (Exception ex)

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Oqtane.Documentation;
@ -9,7 +8,7 @@ using Oqtane.Shared;
namespace Oqtane.Modules.HtmlText.Services
{
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
public class HtmlTextService : ServiceBase, IHtmlTextService, IService
public class HtmlTextService : ServiceBase, IHtmlTextService, IClientService
{
public HtmlTextService(HttpClient http, SiteState siteState) : base(http, siteState) {}
@ -30,9 +29,9 @@ namespace Oqtane.Modules.HtmlText.Services
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
}
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
public async Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmlText)
{
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
}
public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId)

View File

@ -13,7 +13,7 @@ namespace Oqtane.Modules.HtmlText.Services
Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId);
Task AddHtmlTextAsync(Models.HtmlText htmltext);
Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmltext);
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
}

View File

@ -5,42 +5,37 @@
@inject IStringLocalizer<Settings> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="files" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
<div class="col-sm-9">
<select id="files" class="form-select" @bind="@_allowfilemanagement">
<option value="true">@SharedLocalizer["Yes"]</option>
<option value="false">@SharedLocalizer["No"]</option>
</select>
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="dynamictokens" ResourceKey="DynamicTokens" ResourceType="@resourceType" HelpText="Do you wish to allow tokens to be dynamically replaced? Please note that this will affect the performance of your site.">Dynamic Tokens? </Label>
<div class="col-sm-9">
<select id="dynamictokens" class="form-select" @bind="@_dynamictokens">
<option value="true">@SharedLocalizer["Yes"]</option>
<option value="false">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="files" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify If Editors Can Enter Raw HTML">Allow Raw HTML: </Label>
<div class="col-sm-9">
<select id="files" class="form-select" @bind="@_allowrawhtml">
<option value="true">@SharedLocalizer["Yes"]</option>
<option value="false">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
</form>
@code {
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
private string _allowfilemanagement;
private string _allowrawhtml;
@code {
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
private ElementReference form;
private bool validated = false;
private string _dynamictokens;
protected override void OnInitialized()
{
try
{
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
_allowrawhtml = SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true");
}
_dynamictokens = SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false");
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
@ -48,14 +43,13 @@
{
try
{
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
settings = SettingService.SetSetting(settings, "AllowRawHtml", _allowrawhtml);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
settings = SettingService.SetSetting(settings, "DynamicTokens", _dynamictokens);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using Microsoft.JSInterop;
using System.Linq;
using System.Dynamic;
using System.Reflection;
namespace Oqtane.Modules
{
@ -18,6 +19,7 @@ namespace Oqtane.Modules
private Logger _logger;
private string _urlparametersstate;
private Dictionary<string, string> _urlparameters;
private bool _scriptsloaded = false;
protected Logger logger => _logger ?? (_logger = new Logger(this));
@ -34,10 +36,10 @@ namespace Oqtane.Modules
protected PageState PageState { get; set; }
[CascadingParameter]
protected Module ModuleState { get; set; }
protected Models.Module ModuleState { get; set; }
[Parameter]
public ModuleInstance ModuleInstance { get; set; }
public RenderModeBoundary RenderModeBoundary { get; set; }
// optional interface properties
public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
@ -50,6 +52,10 @@ namespace Oqtane.Modules
public virtual List<Resource> Resources { get; set; }
public virtual string RenderMode { get { return RenderModes.Interactive; } } // interactive by default
public virtual bool? Prerender { get { return null; } } // allows the Site Prerender property to be overridden
// url parameters
public virtual string UrlParametersTemplate { get; set; }
@ -77,7 +83,7 @@ namespace Oqtane.Modules
{
if (PageState.Page.Resources != null)
{
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level != ResourceLevel.Site && item.Namespace == type.Namespace).ToList();
resources = PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level == ResourceLevel.Module && item.Namespace == type.Namespace).ToList();
}
}
else // modulecontrolbase
@ -87,22 +93,25 @@ namespace Oqtane.Modules
resources = Resources.Where(item => item.ResourceType == ResourceType.Script).ToList();
}
}
if (resources != null &&resources.Any())
if (resources != null && resources.Any())
{
var interop = new Interop(JSRuntime);
var scripts = new List<object>();
var inline = 0;
foreach (Resource resource in resources)
{
if (!string.IsNullOrEmpty(resource.Url))
if (string.IsNullOrEmpty(resource.RenderMode) || resource.RenderMode == RenderModes.Interactive)
{
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module, location = resource.Location.ToString().ToLower() });
}
else
{
inline += 1;
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Content, resource.Location.ToString().ToLower());
if (!string.IsNullOrEmpty(resource.Url))
{
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
scripts.Add(new { href = url, type = resource.Type ?? "", bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", location = resource.Location.ToString().ToLower(), dataAttributes = resource.DataAttributes });
}
else
{
inline += 1;
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Type ?? "", resource.Content, resource.Location.ToString().ToLower());
}
}
}
if (scripts.Any())
@ -110,6 +119,20 @@ namespace Oqtane.Modules
await interop.IncludeScripts(scripts.ToArray());
}
}
_scriptsloaded = true;
}
}
protected override bool ShouldRender()
{
return PageState?.RenderId == ModuleState?.RenderId;
}
public bool ScriptsLoaded
{
get
{
return _scriptsloaded;
}
}
@ -120,8 +143,18 @@ namespace Oqtane.Modules
return PageState?.Alias.BaseUrl + "/Modules/" + GetType().Namespace + "/";
}
// fingerprint hash code for static assets
public string Fingerprint
{
get
{
return ModuleState.ModuleDefinition.Fingerprint;
}
}
// url methods
// navigate url
public string NavigateUrl()
{
return NavigateUrl(PageState.Page.Path);
@ -137,24 +170,65 @@ namespace Oqtane.Modules
return NavigateUrl(PageState.Page.Path, refresh);
}
public string NavigateUrl(string path, string parameters)
public string NavigateUrl(string path, string querystring)
{
return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters);
return Utilities.NavigateUrl(PageState.Alias.Path, path, querystring);
}
public string NavigateUrl(string path, Dictionary<string, string> querystring)
{
return NavigateUrl(path, Utilities.CreateQueryString(querystring));
}
public string NavigateUrl(string path, bool refresh)
{
return Utilities.NavigateUrl(PageState.Alias.Path, path, refresh ? "refresh" : "");
return NavigateUrl(path, refresh ? "refresh" : "");
}
public string NavigateUrl(int moduleId, string action)
{
return EditUrl(PageState.Page.Path, moduleId, action, "");
}
public string NavigateUrl(int moduleId, string action, string querystring)
{
return EditUrl(PageState.Page.Path, moduleId, action, querystring);
}
public string NavigateUrl(int moduleId, string action, Dictionary<string, string> querystring)
{
return EditUrl(PageState.Page.Path, moduleId, action, querystring);
}
public string NavigateUrl(string path, int moduleId, string action)
{
return EditUrl(path, moduleId, action, "");
}
public string NavigateUrl(string path, int moduleId, string action, string querystring)
{
return EditUrl(path, moduleId, action, querystring);
}
public string NavigateUrl(string path, int moduleId, string action, Dictionary<string, string> querystring)
{
return EditUrl(path, moduleId, action, querystring);
}
// edit url
public string EditUrl(string action)
{
return EditUrl(ModuleState.ModuleId, action);
}
public string EditUrl(string action, string parameters)
public string EditUrl(string action, string querystring)
{
return EditUrl(ModuleState.ModuleId, action, parameters);
return EditUrl(ModuleState.ModuleId, action, querystring);
}
public string EditUrl(string action, Dictionary<string, string> querystring)
{
return EditUrl(ModuleState.ModuleId, action, querystring);
}
public string EditUrl(int moduleId, string action)
@ -162,16 +236,27 @@ namespace Oqtane.Modules
return EditUrl(moduleId, action, "");
}
public string EditUrl(int moduleId, string action, string parameters)
public string EditUrl(int moduleId, string action, string querystring)
{
return EditUrl(PageState.Page.Path, moduleId, action, parameters);
return EditUrl(PageState.Page.Path, moduleId, action, querystring);
}
public string EditUrl(string path, int moduleid, string action, string parameters)
public string EditUrl(int moduleId, string action, Dictionary<string, string> querystring)
{
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters);
return EditUrl(PageState.Page.Path, moduleId, action, querystring);
}
public string EditUrl(string path, int moduleid, string action, string querystring)
{
return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, querystring);
}
public string EditUrl(string path, int moduleid, string action, Dictionary<string, string> querystring)
{
return EditUrl(path, moduleid, action, Utilities.CreateQueryString(querystring));
}
// file url
public string FileUrl(string folderpath, string filename)
{
return FileUrl(folderpath, filename, false);
@ -191,6 +276,8 @@ namespace Oqtane.Modules
return Utilities.FileUrl(PageState.Alias, fileid, download);
}
// image url
public string ImageUrl(int fileid, int width, int height)
{
return ImageUrl(fileid, width, height, "");
@ -261,22 +348,27 @@ namespace Oqtane.Modules
// UI methods
public void AddModuleMessage(string message, MessageType type)
{
ModuleInstance.AddModuleMessage(message, type);
AddModuleMessage(message, type, "top");
}
public void AddModuleMessage(string message, MessageType type, string position)
{
RenderModeBoundary.AddModuleMessage(message, type, position);
}
public void ClearModuleMessage()
{
ModuleInstance.AddModuleMessage("", MessageType.Undefined);
RenderModeBoundary.AddModuleMessage("", MessageType.Undefined);
}
public void ShowProgressIndicator()
{
ModuleInstance.ShowProgressIndicator();
RenderModeBoundary.ShowProgressIndicator();
}
public void HideProgressIndicator()
{
ModuleInstance.HideProgressIndicator();
RenderModeBoundary.HideProgressIndicator();
}
public void SetModuleTitle(string title)
@ -322,6 +414,79 @@ namespace Oqtane.Modules
await interop.ScrollTo(0, 0, "smooth");
}
public string ReplaceTokens(string content)
{
return ReplaceTokens(content, null);
}
public string ReplaceTokens(string content, object obj)
{
var tokens = new List<string>();
var pos = content.IndexOf("[");
if (pos != -1)
{
if (content.IndexOf("]", pos) != -1)
{
var token = content.Substring(pos, content.IndexOf("]", pos) - pos + 1);
if (token.Contains(":"))
{
tokens.Add(token.Substring(1, token.Length - 2));
}
}
pos = content.IndexOf("[", pos + 1);
}
if (tokens.Count != 0)
{
foreach (string token in tokens)
{
var segments = token.Split(":");
if (segments.Length >= 2 && segments.Length <= 3)
{
var objectName = string.Join(":", segments, 0, segments.Length - 1);
var propertyName = segments[segments.Length - 1];
var propertyValue = "";
switch (objectName)
{
case "ModuleState":
propertyValue = ModuleState.GetType().GetProperty(propertyName)?.GetValue(ModuleState, null).ToString();
break;
case "PageState":
propertyValue = PageState.GetType().GetProperty(propertyName)?.GetValue(PageState, null).ToString();
break;
case "PageState:Alias":
propertyValue = PageState.Alias.GetType().GetProperty(propertyName)?.GetValue(PageState.Alias, null).ToString();
break;
case "PageState:Site":
propertyValue = PageState.Site.GetType().GetProperty(propertyName)?.GetValue(PageState.Site, null).ToString();
break;
case "PageState:Page":
propertyValue = PageState.Page.GetType().GetProperty(propertyName)?.GetValue(PageState.Page, null).ToString();
break;
case "PageState:User":
propertyValue = PageState.User?.GetType().GetProperty(propertyName)?.GetValue(PageState.User, null).ToString();
break;
case "PageState:Route":
propertyValue = PageState.Route.GetType().GetProperty(propertyName)?.GetValue(PageState.Route, null).ToString();
break;
default:
if (obj != null && obj.GetType().Name == objectName)
{
propertyValue = obj.GetType().GetProperty(propertyName)?.GetValue(obj, null).ToString();
}
break;
}
if (propertyValue != null)
{
content = content.Replace("[" + token + "]", propertyValue);
}
}
}
}
return content;
}
// logging methods
public async Task Log(Alias alias, LogLevel level, string function, Exception exception, string message, params object[] args)
{
@ -476,5 +641,8 @@ namespace Oqtane.Modules
{
return Utilities.FileUrl(PageState.Alias, fileid, asAttachment);
}
// Referencing ModuleInstance methods from ModuleBase is deprecated. Use the ModuleBase methods instead
public ModuleInstance ModuleInstance { get { return new ModuleInstance(); } }
}
}

View File

@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType>
<Configurations>Debug;Release</Configurations>
<Version>4.0.4</Version>
<Version>6.1.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -12,22 +12,20 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace>
<IsPackable>true</IsPackable>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.3" />
</ItemGroup>
<ItemGroup>

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
@ -13,13 +12,13 @@ using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Oqtane.Documentation;
using Oqtane.Models;
using Oqtane.Modules;
using Oqtane.Services;
using Oqtane.Shared;
using Oqtane.UI;
namespace Oqtane.Client
@ -41,10 +40,10 @@ namespace Oqtane.Client
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
// register auth services
builder.Services.AddOqtaneAuthorization();
builder.Services.AddOqtaneAuthentication();
// register scoped core services
builder.Services.AddOqtaneScopedServices();
builder.Services.AddOqtaneClientScopedServices();
var serviceProvider = builder.Services.BuildServiceProvider();
@ -220,6 +219,16 @@ namespace Oqtane.Client
services.AddScoped(serviceType ?? implementationType, implementationType);
}
}
implementationTypes = assembly.GetInterfaces<IClientService>();
foreach (var implementationType in implementationTypes)
{
if (implementationType.AssemblyQualifiedName != null)
{
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
services.AddScoped(serviceType ?? implementationType, implementationType);
}
}
}
catch
{
@ -248,7 +257,7 @@ namespace Oqtane.Client
var jsRuntime = serviceProvider.GetRequiredService<IJSRuntime>();
var interop = new Interop(jsRuntime);
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICulture.Name;
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
var cultures = await localizationService.GetCulturesAsync(false);

View File

@ -8,20 +8,20 @@
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Oqtane.Client": {
"Oqtane": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:44358/"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,10 +1,8 @@
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Oqtane.Models;
@ -16,12 +14,10 @@ namespace Oqtane.Providers
public class IdentityAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly IServiceProvider _serviceProvider;
private readonly NavigationManager _navigationManager;
public IdentityAuthenticationStateProvider(IServiceProvider serviceProvider, NavigationManager navigationManager)
public IdentityAuthenticationStateProvider(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_navigationManager = navigationManager;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@ -153,7 +153,7 @@
<data name="Integrated" xml:space="preserve">
<value>Integrated</value>
</data>
<data name="Encryption,Text" xml:space="preserve">
<data name="Encryption.Text" xml:space="preserve">
<value>Encryption:</value>
</data>
<data name="Encryption.HelpText" xml:space="preserve">

View File

@ -183,4 +183,13 @@
<data name="Template" xml:space="preserve">
<value>Select a site template</value>
</data>
<data name="Message.Username.Invalid" xml:space="preserve">
<value>The Username Provided Does Not Meet The System Requirement, It Can Only Contains Letters Or Digits.</value>
</data>
<data name="Name.Text" xml:space="preserve">
<value>Full Name:</value>
</data>
<data name="Name.HelpText" xml:space="preserve">
<value>Provide the full name of the host user</value>
</data>
</root>

View File

@ -150,14 +150,11 @@
<data name="Name.HelpText" xml:space="preserve">
<value>Enter the folder name</value>
</data>
<data name="Permissions.HelpText" xml:space="preserve">
<value>Select the permissions you want for the folder</value>
</data>
<data name="Parent.Text" xml:space="preserve">
<value>Parent: </value>
</data>
<data name="Permissions.Text" xml:space="preserve">
<value>Permissions: </value>
<data name="Permissions.Heading" xml:space="preserve">
<value>Permissions</value>
</data>
<data name="DeleteFolder.Header" xml:space="preserve">
<value>Delete Folder</value>
@ -178,7 +175,7 @@
<value>Capacity:</value>
</data>
<data name="ImageSizes.HelpText" xml:space="preserve">
<value>Enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes.</value>
<value>Optionally enter a list of image sizes which can be generated dynamically from uploaded images (ie. 200x200,400x400). Use * to indicate the folder supports all image sizes (not recommended).</value>
</data>
<data name="ImageSizes.Text" xml:space="preserve">
<value>Image Sizes:</value>
@ -195,4 +192,16 @@
<data name="Folder Management" xml:space="preserve">
<value>Folder Management</value>
</data>
<data name="Message.Folder.Duplicate" xml:space="preserve">
<value>Folder Name Specified Already Exists In Parent</value>
</data>
<data name="Settings.Heading" xml:space="preserve">
<value>Settings</value>
</data>
<data name="CacheControl.Text" xml:space="preserve">
<value>Caching:</value>
</data>
<data name="CacheControl.HelpText" xml:space="preserve">
<value>Optionally provide a Cache-Control directive for this folder. For example 'public, max-age=60' indicates that files in this folder should be cached for 60 seconds. Please note that when caching is enabled, changes to files will not be immediately reflected in the UI.</value>
</data>
</root>

View File

@ -165,4 +165,31 @@
<data name="UploadFiles.Text" xml:space="preserve">
<value>Upload Files</value>
</data>
<data name="Files.Heading" xml:space="preserve">
<value>Files</value>
</data>
<data name="ImageExtensions.Text" xml:space="preserve">
<value>Image Extensions:</value>
</data>
<data name="ImageExtensions.HelpText" xml:space="preserve">
<value>Enter a comma separated list of image file extensions</value>
</data>
<data name="UploadableFileExtensions.Text" xml:space="preserve">
<value>Uploadable File Extensions:</value>
</data>
<data name="UploadableFileExtensions.HelpText" xml:space="preserve">
<value>Enter a comma separated list of uploadable file extensions</value>
</data>
<data name="MaxChunkSize.Text" xml:space="preserve">
<value>Max Upload Chunk Size (MB):</value>
</data>
<data name="MaxChunkSize.HelpText" xml:space="preserve">
<value>Files are split into chunks to streamline the upload process. Specify the maximum chunk size in MB (note that higher chunk sizes should only be used on faster networks).</value>
</data>
<data name="Success.SaveSiteSettings" xml:space="preserve">
<value>Settings Saved Successfully</value>
</data>
<data name="Error.SaveSiteSettings" xml:space="preserve">
<value>Error Saving Settings</value>
</data>
</root>

View File

@ -192,4 +192,7 @@
<data name="Once" xml:space="preserve">
<value>Execute Once</value>
</data>
<data name="Message.StartEndDateError" xml:space="preserve">
<value>Start Date cannot be after End Date.</value>
</data>
</root>

View File

@ -144,17 +144,8 @@
<data name="Month" xml:space="preserve">
<value>Month(s)</value>
</data>
<data name="Error.Job.Delete" xml:space="preserve">
<value>Error Deleting Job</value>
</data>
<data name="ViewJobs.Text" xml:space="preserve">
<value>View Logs</value>
</data>
<data name="DeleteJob.Header" xml:space="preserve">
<value>Delete Job</value>
</data>
<data name="DeleteJob.Message" xml:space="preserve">
<value>Are You Sure You Wish To Delete This Job?</value>
<data name="ViewLogs.Text" xml:space="preserve">
<value>View All Logs</value>
</data>
<data name="Frequency" xml:space="preserve">
<value>Frequency</value>
@ -165,9 +156,6 @@
<data name="Stop" xml:space="preserve">
<value>Stop</value>
</data>
<data name="DeleteJob.Text" xml:space="preserve">
<value>Delete</value>
</data>
<data name="EditJob.Text" xml:space="preserve">
<value>Edit</value>
</data>
@ -192,9 +180,6 @@
<data name="Once" xml:space="preserve">
<value>Execute Once</value>
</data>
<data name="Message.NoJobs" xml:space="preserve">
<value>Please Note That After An Initial Installation You Must &lt;a href={0}&gt;Restart&lt;/a&gt; The Application In Order To Activate The Default Scheduled Jobs.</value>
</data>
<data name="Refresh.Text" xml:space="preserve">
<value>Refresh</value>
</data>

View File

@ -132,4 +132,7 @@
<data name="Failed" xml:space="preserve">
<value>Failed</value>
</data>
<data name="Refresh" xml:space="preserve">
<value>Refresh</value>
</data>
</root>

View File

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

View File

@ -204,8 +204,8 @@
<data name="ExternalLoginStatus.DuplicateEmail" xml:space="preserve">
<value>Multiple User Accounts Already Exist With The Email Address Of Your External Login. Please Contact Your Administrator For Further Instructions.</value>
</data>
<data name="ExternalLoginStatus.InvalidEmail" xml:space="preserve">
<value>The External Login Provider Did Not Provide A Valid Email Address For Your Account. Please Contact Your Administrator For Further Instructions.</value>
<data name="ExternalLoginStatus.MissingClaims" xml:space="preserve">
<value>The External Login Provider Did Not Provide All Of The Required Information. Please Contact Your Administrator For Further Instructions.</value>
</data>
<data name="ExternalLoginStatus.ProviderKeyMismatch" xml:space="preserve">
<value>An Error Occurred Verifying Your External Login. Please Contact Your Administrator For Further Instructions.</value>
@ -225,4 +225,10 @@
<data name="ExternalLoginStatus.RemoteFailure" xml:space="preserve">
<value>Your External Login Failed. Please Contact Your Administrator For Further Instructions.</value>
</data>
<data name="ExternalLoginStatus.ReviewClaims" xml:space="preserve">
<value>The Review Claims Option Was Enabled In External Login Settings. Please Visit The Event Log To View The Claims Returned By The Provider.</value>
</data>
<data name="Register" xml:space="preserve">
<value>Register as new user?</value>
</data>
</root>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@ -210,4 +210,16 @@
<data name="Success.SaveSiteSettings" xml:space="preserve">
<value>Settings Saved Successfully</value>
</data>
<data name="DeleteLogs.Header" xml:space="preserve">
<value>Clear Events</value>
</data>
<data name="DeleteLogs.Message" xml:space="preserve">
<value>Are You Sure You Wish To Remove All Log Events?</value>
</data>
<data name="DeleteLogs.Text" xml:space="preserve">
<value>Clear Events</value>
</data>
<data name="Error.DeleteLogs" xml:space="preserve">
<value>Error Deleting Log Events</value>
</data>
</root>

View File

@ -130,16 +130,16 @@
<value>Please Note That The Module Creator Is Only Intended To Be Used In A Development Environment</value>
</data>
<data name="Message.Require.ValidName" xml:space="preserve">
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same Or Contain The Word "Oqtane" ) And Choose A Template</value>
</data>
<data name="Message.Require.ValidDescription" xml:space="preserve">
<value>You Must Provide A Valid Description (ie. No Punctuation)</value>
</data>
<data name="OwnerName.HelpText" xml:space="preserve">
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.</value>
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "oqtane".</value>
</data>
<data name="ModuleName.HelpText" xml:space="preserve">
<value>Enter a name for this module. It should not contain spaces or punctuation.</value>
<value>Enter a name for this module. It should not contain spaces or punctuation or contain the word "oqtane".</value>
</data>
<data name="Description.HelpText" xml:space="preserve">
<value>Enter a short description for the module</value>
@ -171,4 +171,4 @@
<data name="Success.Module.Create" xml:space="preserve">
<value>The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must &lt;a href={0}&gt;Restart&lt;/a&gt; Your Application To Activate The Module.</value>
</data>
</root>
</root>

View File

@ -228,16 +228,10 @@
<data name="View License" xml:space="preserve">
<value>View License</value>
</data>
<data name="Error.Validate" xml:space="preserve">
<value>Error Validating Package</value>
<data name="Browse" xml:space="preserve">
<value>Browse</value>
</data>
<data name="Message.Download" xml:space="preserve">
<value>Package Version Has Been Verified. Please Select The Download Button To Obtain The Package.</value>
</data>
<data name="Message.Validate" xml:space="preserve">
<value>This Package Version Has Not Been Registered In The Oqtane Marketplace Or You Do Not Have The Right To Use It From This Installation</value>
</data>
<data name="Validate" xml:space="preserve">
<value>Validate</value>
<data name="Pages.Heading" xml:space="preserve">
<value>Pages</value>
</data>
</root>

View File

@ -127,7 +127,7 @@
<value>Error Downloading Module</value>
</data>
<data name="Confirm.Module.Delete" xml:space="preserve">
<value>Are You Sure You Wish To Delete The {0} Module?</value>
<value>Are You Sure You Wish To Uninstall The {0} Module?</value>
</data>
<data name="Error.Module.Load" xml:space="preserve">
<value>Error Loading Modules</value>
@ -142,10 +142,10 @@
<value>Install Module</value>
</data>
<data name="DeleteModule.Header" xml:space="preserve">
<value>Delete Module</value>
<value>Uninstall Module</value>
</data>
<data name="DeleteModule.Text" xml:space="preserve">
<value>Delete</value>
<value>Uninstall</value>
</data>
<data name="InUse" xml:space="preserve">
<value>In Use?</value>

View File

@ -156,7 +156,37 @@
<data name="Module.Text" xml:space="preserve">
<value>Module:</value>
</data>
<data name="Module Settings" xml:space="preserve">
<data name="ModuleSettings.Heading" xml:space="preserve">
<value>Module Settings</value>
</data>
<data name="Pane.HelpText" xml:space="preserve">
<value>The pane where the module will be displayed</value>
</data>
<data name="Pane.Text" xml:space="preserve">
<value>Pane:</value>
</data>
<data name="EffectiveDate.HelpText" xml:space="preserve">
<value>The date that this module is active</value>
</data>
<data name="EffectiveDate.Text" xml:space="preserve">
<value>Effective Date: </value>
</data>
<data name="ExpiryDate.HelpText" xml:space="preserve">
<value>The date that this module expires</value>
</data>
<data name="ExpiryDate.Text" xml:space="preserve">
<value>Expiry Date: </value>
</data>
<data name="Permissions.Text" xml:space="preserve">
<value>Permissions</value>
</data>
<data name="Permissions.Heading" xml:space="preserve">
<value>Permissions</value>
</data>
<data name="ContainerSettings.Heading" xml:space="preserve">
<value>Container Settings</value>
</data>
<data name="ModuleSettings.Title" xml:space="preserve">
<value>Module Settings</value>
</data>
</root>

View File

@ -255,4 +255,16 @@
<data name="Theme.Heading" xml:space="preserve">
<value>Theme Settings</value>
</data>
</root>
<data name="EffectiveDate.HelpText" xml:space="preserve">
<value>The date that this page is active</value>
</data>
<data name="EffectiveDate.Text" xml:space="preserve">
<value>Effective Date: </value>
</data>
<data name="ExpiryDate.HelpText" xml:space="preserve">
<value>The date that this page expires</value>
</data>
<data name="ExpiryDate.Text" xml:space="preserve">
<value>Expiry Date: </value>
</data>
</root>

View File

@ -169,7 +169,7 @@
<value>Select whether the page is part of the site navigation or hidden</value>
</data>
<data name="UrlPath.HelpText" xml:space="preserve">
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'.</value>
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. Please note that spaces and punctuation will be replaced by a dash. If the page is intended to be the root path specify '/'.</value>
</data>
<data name="Redirect.HelpText" xml:space="preserve">
<value>Optionally enter a url which this page should redirect to when a user navigates to it</value>
@ -285,4 +285,22 @@
<data name="ThemeChanged.Message" xml:space="preserve">
<value>Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site</value>
</data>
<data name="EffectiveDate.HelpText" xml:space="preserve">
<value>The date that this page is active</value>
</data>
<data name="EffectiveDate.Text" xml:space="preserve">
<value>Effective Date: </value>
</data>
<data name="ExpiryDate.HelpText" xml:space="preserve">
<value>The date that this page expires</value>
</data>
<data name="ExpiryDate.Text" xml:space="preserve">
<value>Expiry Date: </value>
</data>
<data name="PersonalizedUrlPath.Text" xml:space="preserve">
<value>Url Path:</value>
</data>
<data name="PersonalizedUrlPath.HelpText" xml:space="preserve">
<value>Provide a url path for your personalized page. Please note that spaces and punctuation will be replaced by a dash.</value>
</data>
</root>

Some files were not shown because too many files have changed in this diff Show More