/ src / modules / cmdpal / ext / SamplePagesExtension / Pages / SampleCommentsPage.cs
SampleCommentsPage.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  
  5  using System.Collections.Generic;
  6  using System.Diagnostics.CodeAnalysis;
  7  using System.Text.Json;
  8  using System.Text.Json.Nodes;
  9  using System.Text.Json.Serialization;
 10  using Microsoft.CommandPalette.Extensions;
 11  using Microsoft.CommandPalette.Extensions.Toolkit;
 12  
 13  namespace SamplePagesExtension;
 14  
 15  internal sealed partial class SampleCommentsPage : ContentPage
 16  {
 17      private readonly TreeContent myContentTree;
 18  
 19      public override IContent[] GetContent() => [myContentTree];
 20  
 21      public SampleCommentsPage()
 22      {
 23          Name = "View Posts";
 24          Icon = new IconInfo("\uE90A"); // Comment
 25  
 26          myContentTree = new()
 27          {
 28              RootContent = new MarkdownContent()
 29              {
 30                  Body = """
 31  # Example of a thread of comments
 32  You can use TreeContent in combination with FormContent to build a structure like a page with comments.
 33  
 34  The forms on this page use the AdaptiveCard `Action.ShowCard` action to show a nested, hidden card on the form.
 35  """,
 36              },
 37  
 38              Children = [
 39                  new PostContent("First")
 40                  {
 41                      Replies = [
 42                          new PostContent("Oh very insightful. I hadn't considered that"),
 43                          new PostContent("Second"),
 44                          new PostContent("ah the ol switcheroo"),
 45                      ],
 46                  },
 47                  new PostContent("First\nEDIT: shoot")
 48                  {
 49                      Replies = [
 50                          new PostContent("delete this"),
 51                      ],
 52                  },
 53                  new PostContent("Do you think they get the picture")
 54                  {
 55                      Replies = [
 56                          new PostContent("Probably! Now go build and be happy"),
 57                      ],
 58                  }
 59              ],
 60          };
 61      }
 62  }
 63  
 64  [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
 65  internal sealed partial class PostContent : TreeContent
 66  {
 67      public List<IContent> Replies { get; init; } = [];
 68  
 69      private readonly ToastStatusMessage _toast = new(new StatusMessage() { Message = "Reply posted", State = MessageState.Success });
 70  
 71      public PostContent(string body)
 72      {
 73          RootContent = new PostForm(body, this);
 74      }
 75  
 76      public override IContent[] GetChildren() => Replies.ToArray();
 77  
 78      public void Post()
 79      {
 80          RaiseItemsChanged(Replies.Count);
 81          _toast.Show();
 82      }
 83  }
 84  
 85  [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
 86  internal sealed partial class PostForm : FormContent
 87  {
 88      private readonly PostContent _parent;
 89  
 90      public PostForm(string postBody, PostContent parent)
 91      {
 92          _parent = parent;
 93          TemplateJson = """
 94  {
 95      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
 96      "type": "AdaptiveCard",
 97      "version": "1.6",
 98      "body": [
 99          {
100              "type": "TextBlock",
101              "text": "${postBody}",
102              "wrap": true
103          }
104      ],
105      "actions": [
106          {
107              "type": "Action.ShowCard",
108              "title": "${replyCard.title}",
109              "card": {
110                  "type": "AdaptiveCard",
111                  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
112                  "version": "1.6",
113                  "body": [
114                      {
115                          "type": "Container",
116                          "id": "${replyCard.idPrefix}Properties",
117                          "items": [
118                              {
119                                  "$data": "${replyCard.fields}",
120                                  "type": "Input.Text",
121                                  "label": "${label}",
122                                  "id": "${id}",
123                                  "isRequired": "${required}",
124                                  "isMultiline": true,
125                                  "errorMessage": "'${label}' is required"
126                              }
127                          ]
128                      }
129                  ],
130                  "actions": [
131                      {
132                          "type": "Action.Submit",
133                          "title": "Post"
134                      }
135                  ]
136              }
137          },
138          {
139              "type": "Action.Submit",
140              "title": "Favorite"
141          },
142          {
143              "type": "Action.Submit",
144              "title": "View on web"
145          }
146      ]
147  }
148  """;
149          DataJson = $$"""
150  {
151      "postBody": {{JsonSerializer.Serialize(postBody, JsonSerializationContext.Default.String)}},
152      "replyCard": {
153          "title": "Reply",
154          "idPrefix": "reply",
155          "fields": [
156              {
157                  "label": "Reply",
158                  "id": "ReplyBody",
159                  "required": true,
160                  "placeholder": "Write a reply here"
161              }
162          ]
163      }
164  }
165  """;
166      }
167  
168      public override ICommandResult SubmitForm(string payload)
169      {
170          var data = JsonNode.Parse(payload);
171          _ = data;
172          var reply = data["ReplyBody"];
173          var s = reply?.AsValue()?.ToString();
174          if (!string.IsNullOrEmpty(s))
175          {
176              _parent.Replies.Add(new PostContent(s));
177              _parent.Post();
178          }
179  
180          return CommandResult.KeepOpen();
181      }
182  }
183  
184  [JsonSerializable(typeof(float))]
185  [JsonSerializable(typeof(int))]
186  [JsonSerializable(typeof(string))]
187  [JsonSerializable(typeof(bool))]
188  [JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true)]
189  [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
190  internal sealed partial class JsonSerializationContext : JsonSerializerContext
191  {
192  }