Skip to content

Commit

Permalink
Merge pull request #4 from seangwright/feat/remove-wrapping-element-p…
Browse files Browse the repository at this point in the history
…roperty

Feature: Dancing Goat example project, Outline tag helper RemoveElement property
  • Loading branch information
seangwright authored Oct 28, 2024
2 parents a331c52 + 2602b36 commit bd064ae
Show file tree
Hide file tree
Showing 301 changed files with 30,309 additions and 7 deletions.
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Copyright>Copyright © $(Company) $([System.DateTime]::Now.Year)</Copyright>
<Trademark>$(Company)™</Trademark>
<Product>XperienceCommunity.PreviewComponentOutlines</Product>
<VersionPrefix>4.0.0</VersionPrefix>
<VersionPrefix>4.1.0</VersionPrefix>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Title>$(Product)</Title>
<PackageProjectUrl>https://github.com/seangwright/xperience-community-preview-component-outlines</PackageProjectUrl>
Expand All @@ -29,6 +29,7 @@
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<HotChocolateImplicitUsings>disable</HotChocolateImplicitUsings>
</PropertyGroup>

<PropertyGroup Condition=" $(Configuration) == 'Release' ">
Expand Down
7 changes: 5 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Kentico.Xperience.WebApp" Version="29.6.0" />
<PackageVersion Include="kentico.xperience.admin" Version="29.6.0" />
<PackageVersion Include="kentico.xperience.azurestorage" Version="29.6.0" />
<PackageVersion Include="kentico.xperience.imageprocessing" Version="29.6.0" />
<PackageVersion Include="Kentico.Xperience.Core.Tests" Version="29.6.0" />

<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="NUnit" Version="4.2.2" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageVersion Include="NUnit.Analyzers" Version="4.3.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Kentico.Xperience.Core.Tests" Version="29.6.0" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.1" />
</ItemGroup>
</Project>
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,47 @@ In each Page Builder component you would like to have an outline and label, add
Example:

```html
<!-- _SingleColumnSection.cshtml -->
<!-- SingleColumnSection.cshtml -->

<section xpc-preview-outline="Single Column Section">
<!-- ... other markup -->
</section>
```

If you added a wrapping HTML element to apply the tag helper to the component and you want to remove that element
when rendering for a live website request, you can use the `xpc-preview-outline-remove-element` attribute:

```html
<!-- SingleColumnSection.cshtml -->

<div
xpc-preview-outline="Single Column Section"
xpc-preview-outline-remove-element="true"
>
<section>
<widget-zone name="left" />
</section>

<section>
<widget-zone name="right" />
</section>
</div>
```

The rendered output will include the children elements but not the wrapping parent:

```html
<!-- SingleColumnSection.cshtml -->

<section>
<widget-zone name="left" />
</section>

<section>
<widget-zone name="right" />
</section>
```

## Contributions

If you discover a problem, please [open an issue](https://github.com/seangwright/xperience-community-preview-component-outlines/issues/new).
Expand Down
9 changes: 9 additions & 0 deletions XperienceCommunity.PreviewComponentOutlines.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{8DE5E965
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{BC45E830-89AE-41A0-A42B-00664EDE1FAA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DancingGoat", "examples\DancingGoat\DancingGoat.csproj", "{69D863B8-37B7-4374-B2F4-37F8A906B414}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -43,13 +47,18 @@ Global
{8F3A022D-097A-45D4-B80D-A4C154BC05F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F3A022D-097A-45D4-B80D-A4C154BC05F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F3A022D-097A-45D4-B80D-A4C154BC05F6}.Release|Any CPU.Build.0 = Release|Any CPU
{69D863B8-37B7-4374-B2F4-37F8A906B414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69D863B8-37B7-4374-B2F4-37F8A906B414}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69D863B8-37B7-4374-B2F4-37F8A906B414}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69D863B8-37B7-4374-B2F4-37F8A906B414}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{47B45064-794E-4300-817F-2FE8FD539745} = {5DD1ED9B-8E1D-4A1B-89CC-5A060CB67A95}
{8F3A022D-097A-45D4-B80D-A4C154BC05F6} = {4C2A262F-3F3D-4834-A241-404A90C90F1D}
{69D863B8-37B7-4374-B2F4-37F8A906B414} = {BC45E830-89AE-41A0-A42B-00664EDE1FAA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF74E9A2-EE1C-48CA-A59F-07AA75AEE02F}
Expand Down
14 changes: 14 additions & 0 deletions examples/DancingGoat/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": 1,
"isRoot": true,
"tools": {
"kentico.xperience.dbmanager": {
"version": "29.6.0",
"commands": [
"kentico-xperience-dbmanager"
]
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using CMS.Base;
using CMS.ContactManagement;
using CMS.Core;
using CMS.DataEngine;
using CMS.DataProtection;
using CMS.Membership;
using CMS.OnlineForms;
using CMS.Websites;

using DancingGoat.AdminComponents;
using DancingGoat.Helpers.Generator;

using Kentico.Forms.Web.Mvc.Internal;
using Kentico.Xperience.Admin.Base;
using Kentico.Xperience.Admin.Base.UIPages;

[assembly: UIApplication(SampleDataGeneratorApplication.IDENTIFIER, typeof(SampleDataGeneratorApplication), "sample-data-generator", "Sample data generator", BaseApplicationCategories.CONFIGURATION, Icons.CogwheelSquare, TemplateNames.OVERVIEW)]

namespace DancingGoat.AdminComponents
{
/// <summary>
/// Represents an application for sample data generation.
/// </summary>
[UIPermission(SystemPermissions.VIEW)]
public class SampleDataGeneratorApplication : OverviewPageBase
{
/// <summary>
/// Unique identifier of application.
/// </summary>
public const string IDENTIFIER = "Kentico.Xperience.Application.SampleDataGenerator";

private const int DANCING_GOAT_WEBSITE_CHANNEL_ID = 1;
private const string FORM_NAME = "DancingGoatCoffeeSampleList";
private const string FORM_FIELD_NAME = "Consent";
private const string DATA_PROTECTION_SETTINGS_KEY = "DataProtectionSamplesEnabled";

private readonly IFormBuilderConfigurationSerializer formBuilderConfigurationSerializer;
private readonly IEventLogService eventLogService;
private readonly IInfoProvider<ConsentInfo> consentInfoProvider;
private readonly IInfoProvider<BizFormInfo> bizFormInfoProvider;
private readonly IInfoProvider<ContactGroupInfo> contactGroupInfoProvider;
private readonly IInfoProvider<SettingsKeyInfo> settingsKeyInfoProvider;
private readonly IInfoProvider<WebsiteChannelInfo> websiteChannelInfoProvider;


/// <summary>
/// Initializes a new instance of the <see cref="SampleDataGeneratorApplication"/> class.
/// </summary>
/// <param name="formBuilderConfigurationSerializer">Form builder configuration serializer.</param>
/// <param name="eventLogService">Event log service.</param>
/// <param name="consentInfoProvider">Consent info provider.</param>
/// <param name="bizFormInfoProvider">BizForm info provider.</param>
/// <param name="contactGroupInfoProvider">Contact group info provider.</param>
/// <param name="settingsKeyInfoProvider">Settings key info provider.</param>
/// <param name="websiteChannelInfoProvider">Website channel info provider.</param>
public SampleDataGeneratorApplication(
IFormBuilderConfigurationSerializer formBuilderConfigurationSerializer,
IEventLogService eventLogService,
IInfoProvider<ConsentInfo> consentInfoProvider,
IInfoProvider<BizFormInfo> bizFormInfoProvider,
IInfoProvider<ContactGroupInfo> contactGroupInfoProvider,
IInfoProvider<SettingsKeyInfo> settingsKeyInfoProvider,
IInfoProvider<WebsiteChannelInfo> websiteChannelInfoProvider)
{
this.formBuilderConfigurationSerializer = formBuilderConfigurationSerializer;
this.eventLogService = eventLogService;
this.consentInfoProvider = consentInfoProvider;
this.bizFormInfoProvider = bizFormInfoProvider;
this.contactGroupInfoProvider = contactGroupInfoProvider;
this.settingsKeyInfoProvider = settingsKeyInfoProvider;
this.websiteChannelInfoProvider = websiteChannelInfoProvider;
}


public override Task ConfigurePage()
{
PageConfiguration.CardGroups.AddCardGroup().AddCard(GetGdprCard());

PageConfiguration.Caption = "Sample data generator";

return base.ConfigurePage();
}


[PageCommand(Permission = SystemPermissions.VIEW)]
public async Task<ICommandResponse> GenerateGdprSampleData()
{
try
{
new TrackingConsentGenerator(consentInfoProvider).Generate();
new FormConsentGenerator(formBuilderConfigurationSerializer, consentInfoProvider, bizFormInfoProvider).Generate(FORM_NAME, FORM_FIELD_NAME);
new FormContactGroupGenerator(contactGroupInfoProvider).Generate();

EnableDataProtectionSamples();

await SetChannelDefaultCookieLevelToEssential(DANCING_GOAT_WEBSITE_CHANNEL_ID);
}
catch (Exception ex)
{
eventLogService.LogException("SampleDataGenerator", "GDPR", ex);

return Response().AddErrorMessage("GDPR sample data generator failed. See event log for more details.");
}

return Response().AddSuccessMessage("Generating data finished successfully.");
}


private void EnableDataProtectionSamples()
{
var dataProtectionSamplesEnabledSettingsKey = settingsKeyInfoProvider.Get(DATA_PROTECTION_SETTINGS_KEY);
if (dataProtectionSamplesEnabledSettingsKey?.KeyValue.ToBoolean(false) ?? false)
{
return;
}

var keyInfo = new SettingsKeyInfo
{
KeyName = DATA_PROTECTION_SETTINGS_KEY,
KeyDisplayName = DATA_PROTECTION_SETTINGS_KEY,
KeyType = "boolean",
KeyValue = "True",
KeyIsHidden = true,
};

settingsKeyInfoProvider.Set(keyInfo);
}


private OverviewCard GetGdprCard()
{
return new OverviewCard
{
Headline = "Set up data protection (GDPR) demo",
Actions = new[]
{
new Kentico.Xperience.Admin.Base.Action(ActionType.Command)
{
Label = "Generate",
Parameter = nameof(GenerateGdprSampleData),
ButtonColor = ButtonColor.Secondary
}
},
Components = new List<IOverviewCardComponent>()
{
new StringContentCardComponent
{
Content = @"Generates data and enables demonstration of giving consents, personal data portability, right to access, and right to be forgotten features.
Once enabled, the demo functionality cannot be disabled. Use on demo instances only."
}
}
};
}


private async Task SetChannelDefaultCookieLevelToEssential(int websiteChannelId)
{
var websiteChannel = await websiteChannelInfoProvider.GetAsync(websiteChannelId);

if (websiteChannel is not null)
{
websiteChannel.WebsiteChannelDefaultCookieLevel = Kentico.Web.Mvc.CookieLevel.Essential.Level;
websiteChannel.Generalized.SetObject();
}
}
}
}
24 changes: 24 additions & 0 deletions examples/DancingGoat/Components/ComponentIdentifiers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace DancingGoat
{
/// <summary>
/// Encapsulated identifiers of components.
/// </summary>
public static class ComponentIdentifiers
{
// Widgets
public const string CTA_BUTTON_WIDGET = "DancingGoat.General.CTAButtonWidget";
public const string TESTIMONIAL_WIDGET = "DancingGoat.LandingPage.TestimonialWidget";

// Sections
public const string SINGLE_COLUMN_SECTION = "DancingGoat.SingleColumnSection";
public const string TWO_COLUMN_SECTION = "DancingGoat.TwoColumnSection";
public const string THREE_COLUMN_SECTION = "DancingGoat.ThreeColumnSection";
public const string SECTION_75_25 = "DancingGoat.Section_75_25";
public const string SECTION_25_75 = "DancingGoat.Section_25_75";

// Page templates
public const string LANDING_PAGE_SINGLE_COLUMN_TEMPLATE = "DancingGoat.LandingPageSingleColumn";
public const string ARTICLE_TEMPLATE = "DancingGoat.Article";
public const string ARTICLE_WITH_SIDEBAR_TEMPLATE = "DancingGoat.ArticleWithSidebar";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using DancingGoat.Components.FormSections.TitledSection;

using Kentico.Forms.Web.Mvc;

[assembly: RegisterFormSection("DancingGoat.TitledSection", "Section with title", "~/Components/FormSections/TitledSection/_TitledSection.cshtml", Description = "Single-column section with one zone and an editable title", IconClass = "icon-rectangle-a", PropertiesType = typeof(TitledSectionProperties))]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Kentico.Forms.Web.Mvc;

using Kentico.Xperience.Admin.Base.FormAnnotations;

namespace DancingGoat.Components.FormSections.TitledSection
{
public class TitledSectionProperties : IFormSectionProperties
{
[RichTextEditorComponent(Label = "Title")]
public string Title { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@using Kentico.Forms.Web.Mvc
@using DancingGoat.Components.FormSections.TitledSection
@using Kentico.Web.Mvc;
@using Kentico.PageBuilder.Web.Mvc


@model FormSectionViewModel<TitledSectionProperties>

@if (!string.IsNullOrEmpty(Model?.Properties?.Title))
{
<div class="ktc-section-title">
@Html.Raw(Html.Kentico().ResolveRichText(Model.Properties.Title))
</div>
}

<div class="row">
<div class="col-md-12">
@await Html.Kentico().FormZoneAsync()
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace DancingGoat.InlineEditors
{
/// <summary>
/// View model for Color picker editor.
/// </summary>
public sealed class ColorPickerEditorViewModel : InlineEditorViewModel
{
/// <summary>
/// Color CSS class.
/// </summary>
public string ColorCssClass { get; set; }
}
}
Loading

0 comments on commit bd064ae

Please sign in to comment.