Browse Source

Annotate field properties.

pull/349/head
Sebastian Stehle 7 years ago
parent
commit
8ca8e0ae9a
  1. 6
      extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs
  2. 4
      extensions/Squidex.Extensions/Actions/AzureQueue/AzureQueueAction.cs
  3. 11
      extensions/Squidex.Extensions/Actions/Discourse/DiscourseAction.cs
  4. 9
      extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs
  5. 13
      extensions/Squidex.Extensions/Actions/Email/EmailAction.cs
  6. 2
      extensions/Squidex.Extensions/Actions/Fastly/FastlyAction.cs
  7. 10
      extensions/Squidex.Extensions/Actions/Medium/MediumAction.cs
  8. 3
      extensions/Squidex.Extensions/Actions/Prerender/PrerenderAction.cs
  9. 4
      extensions/Squidex.Extensions/Actions/Slack/SlackAction.cs
  10. 3
      extensions/Squidex.Extensions/Actions/Twitter/TweetAction.cs
  11. 5
      extensions/Squidex.Extensions/Actions/Webhook/WebhookAction.cs
  12. 16
      extensions/Squidex.Extensions/SquidexExtensions.cs
  13. 8
      src/Squidex/Config/Web/WebServices.cs
  14. 22
      src/Squidex/Pipeline/Plugins/PluginExtensions.cs
  15. 5
      src/Squidex/WebStartup.cs
  16. 12
      src/Squidex/app/features/rules/pages/rules/rule-element.component.html
  17. 9
      src/Squidex/app/features/rules/pages/rules/rule-element.component.scss
  18. 8
      src/Squidex/app/features/rules/pages/rules/rules-page.component.ts
  19. 41
      src/Squidex/app/shared/services/rules.service.spec.ts
  20. 49
      src/Squidex/app/shared/services/rules.service.ts

6
extensions/Squidex.Extensions/Actions/Algolia/AlgoliaAction.cs

@ -22,14 +22,20 @@ namespace Squidex.Extensions.Actions.Algolia
{
[Required]
[Display(Name = "Application Id", Description = "The application ID.")]
[DataType(DataType.Text)]
[Formattable]
public string AppId { get; set; }
[Required]
[Display(Name = "Api Key", Description = "The API key to grant access to Squidex.")]
[DataType(DataType.Text)]
[Formattable]
public string ApiKey { get; set; }
[Required]
[Display(Name = "Index Name", Description = "The name of the index.")]
[DataType(DataType.Text)]
[Formattable]
public string IndexName { get; set; }
}
}

4
extensions/Squidex.Extensions/Actions/AzureQueue/AzureQueueAction.cs

@ -25,10 +25,14 @@ namespace Squidex.Extensions.Actions.AzureQueue
{
[Required]
[Display(Name = "Connection String", Description = "The connection string to the storage account.")]
[DataType(DataType.Text)]
[Formattable]
public string ConnectionString { get; set; }
[Required]
[Display(Name = "Queue", Description = "The name of the queue.")]
[DataType(DataType.Text)]
[Formattable]
public string Queue { get; set; }
protected override IEnumerable<ValidationError> CustomValidate()

11
extensions/Squidex.Extensions/Actions/Discourse/DiscourseAction.cs

@ -24,28 +24,37 @@ namespace Squidex.Extensions.Actions.Discourse
{
[AbsoluteUrl]
[Required]
[Display(Name = "Url", Description = "he url to the discourse server.")]
[Display(Name = "Url", Description = "The url to the discourse server.")]
[DataType(DataType.Url)]
public Uri Url { get; set; }
[Required]
[Display(Name = "Api Key", Description = "The api key to authenticate to your discourse server.")]
[DataType(DataType.Text)]
public string ApiKey { get; set; }
[Required]
[Display(Name = "Api Username", Description = "The api username to authenticate to your discourse server.")]
[DataType(DataType.Text)]
public string ApiUsername { get; set; }
[Required]
[Display(Name = "Text", Description = "The text as markdown.")]
[DataType(DataType.MultilineText)]
[Formattable]
public string Text { get; set; }
[Display(Name = "Title", Description = "The optional title when creating new topics.")]
[DataType(DataType.Text)]
[Formattable]
public string Title { get; set; }
[Display(Name = "Topic", Description = "The optional topic id.")]
[DataType(DataType.Custom)]
public int? Topic { get; set; }
[Display(Name = "Category", Description = "The optional category id.")]
[DataType(DataType.Custom)]
public int? Category { get; set; }
}
}

9
extensions/Squidex.Extensions/Actions/ElasticSearch/ElasticSearchAction.cs

@ -25,20 +25,29 @@ namespace Squidex.Extensions.Actions.ElasticSearch
[AbsoluteUrl]
[Required]
[Display(Name = "Host", Description = "The hostname of the elastic search instance or cluster.")]
[DataType(DataType.Url)]
public Uri Host { get; set; }
[Required]
[Display(Name = "Index Name", Description = "The name of the index.")]
[DataType(DataType.Text)]
[Formattable]
public string IndexName { get; set; }
[Required]
[Display(Name = "Index Type", Description = "The name of the index type.")]
[DataType(DataType.Text)]
[Formattable]
public string IndexType { get; set; }
[Display(Name = "Username", Description = "The optional username.")]
[DataType(DataType.Text)]
[Formattable]
public string Username { get; set; }
[Display(Name = "Password", Description = "The optional password.")]
[DataType(DataType.Password)]
[Formattable]
public string Password { get; set; }
}
}

13
extensions/Squidex.Extensions/Actions/Email/EmailAction.cs

@ -22,38 +22,51 @@ namespace Squidex.Extensions.Actions.Email
{
[Required]
[Display(Name = "ServerHost", Description = "The IP address or host to the SMTP server.")]
[DataType(DataType.Text)]
public string ServerHost { get; set; }
[Required]
[Display(Name = "ServerPort", Description = "The port to the SMTP server.")]
[DataType(DataType.Custom)]
public int ServerPort { get; set; }
[Required]
[Display(Name = "ServerUseSsl", Description = "Specify whether the SMPT client uses Secure Sockets Layer (SSL) to encrypt the connection.")]
[DataType(DataType.Custom)]
public bool ServerUseSsl { get; set; }
[Required]
[Display(Name = "ServerUsername", Description = "The username for the SMTP server.")]
[DataType(DataType.Text)]
public string ServerUsername { get; set; }
[Required]
[Display(Name = "ServerPassword", Description = "The password for the SMTP server.")]
[DataType(DataType.Password)]
public string ServerPassword { get; set; }
[Required]
[Display(Name = "MessageFrom", Description = "The email sending address.")]
[DataType(DataType.Text)]
[Formattable]
public string MessageFrom { get; set; }
[Required]
[Display(Name = "MessageTo", Description = "The email message will be sent to.")]
[DataType(DataType.Text)]
[Formattable]
public string MessageTo { get; set; }
[Required]
[Display(Name = "MessageSubject", Description = "The subject line for this email message.")]
[DataType(DataType.Text)]
[Formattable]
public string MessageSubject { get; set; }
[Required]
[Display(Name = "MessageBody", Description = "The message body.")]
[DataType(DataType.MultilineText)]
[Formattable]
public string MessageBody { get; set; }
}
}

2
extensions/Squidex.Extensions/Actions/Fastly/FastlyAction.cs

@ -22,10 +22,12 @@ namespace Squidex.Extensions.Actions.Fastly
{
[Required]
[Display(Name = "Api Key", Description = "The API key to grant access to Squidex.")]
[DataType(DataType.Text)]
public string ApiKey { get; set; }
[Required]
[Display(Name = "Service Id", Description = "The ID of the fastly service.")]
[DataType(DataType.Text)]
public string ServiceId { get; set; }
}
}

10
extensions/Squidex.Extensions/Actions/Medium/MediumAction.cs

@ -22,26 +22,36 @@ namespace Squidex.Extensions.Actions.Medium
{
[Required]
[Display(Name = "Access Token", Description = "The self issued access token.")]
[DataType(DataType.Text)]
public string AccessToken { get; set; }
[Required]
[Display(Name = "Title", Description = "The title, used for the url.")]
[DataType(DataType.Text)]
[Formattable]
public string Title { get; set; }
[Required]
[Display(Name = "Content", Description = "The content, either html or markdown.")]
[DataType(DataType.MultilineText)]
[Formattable]
public string Content { get; set; }
[Display(Name = "Canonical Url", Description = "The original home of this content, if it was originally published elsewhere.")]
[DataType(DataType.Text)]
[Formattable]
public string CanonicalUrl { get; set; }
[Display(Name = "PublicationId", Description = "Optional publication id.")]
[DataType(DataType.Text)]
public string PublicationId { get; set; }
[Display(Name = "Tags", Description = "The optional comma separated list of tags.")]
[DataType(DataType.Text)]
public string Tags { get; set; }
[Display(Name = "Is Html", Description = "Indicates whether the content is markdown or html.")]
[DataType(DataType.Custom)]
public bool IsHtml { get; set; }
}
}

3
extensions/Squidex.Extensions/Actions/Prerender/PrerenderAction.cs

@ -22,10 +22,13 @@ namespace Squidex.Extensions.Actions.Prerender
{
[Required]
[Display(Name = "Token", Description = "The prerender token from your account.")]
[DataType(DataType.Text)]
[Formattable]
public string Token { get; set; }
[Required]
[Display(Name = "Url", Description = "The url to recache.")]
[DataType(DataType.Text)]
public string Url { get; set; }
}
}

4
extensions/Squidex.Extensions/Actions/Slack/SlackAction.cs

@ -25,10 +25,14 @@ namespace Squidex.Extensions.Actions.Slack
[AbsoluteUrl]
[Required]
[Display(Name = "Webhook Url", Description = "The slack webhook url.")]
[DataType(DataType.Text)]
[Formattable]
public Uri WebhookUrl { get; set; }
[Required]
[Display(Name = "Text", Description = "The text that is sent as message to slack.")]
[DataType(DataType.MultilineText)]
[Formattable]
public string Text { get; set; }
}
}

3
extensions/Squidex.Extensions/Actions/Twitter/TweetAction.cs

@ -22,14 +22,17 @@ namespace Squidex.Extensions.Actions.Twitter
{
[Required]
[Display(Name = "Access Token", Description = " The generated access token.")]
[DataType(DataType.Text)]
public string AccessToken { get; set; }
[Required]
[Display(Name = "Access Secret", Description = " The generated access secret.")]
[DataType(DataType.Text)]
public string AccessSecret { get; set; }
[Required]
[Display(Name = "Text", Description = "The text that is sent as tweet to twitter.")]
[DataType(DataType.MultilineText)]
public string Text { get; set; }
}
}

5
extensions/Squidex.Extensions/Actions/Webhook/WebhookAction.cs

@ -24,10 +24,13 @@ namespace Squidex.Extensions.Actions.Webhook
{
[AbsoluteUrl]
[Required]
[Display(Name = "Url", Description = "he url to the webhook.")]
[Display(Name = "Url", Description = "The url to the webhook.")]
[DataType(DataType.Text)]
[Formattable]
public Uri Url { get; set; }
[Display(Name = "Shared Secret", Description = "The shared secret that is used to calculate the signature.")]
[DataType(DataType.Text)]
public string SharedSecret { get; set; }
}
}

16
extensions/Squidex.Extensions/SquidexExtensions.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Reflection;
namespace Squidex.Extensions
{
public static class SquidexExtensions
{
public static readonly Assembly Assembly = typeof(SquidexExtensions).Assembly;
}
}

8
src/Squidex/Config/Web/WebServices.cs

@ -6,17 +6,19 @@
// ==========================================================================
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Config.Domain;
using Squidex.Infrastructure.DependencyInjection;
using Squidex.Pipeline;
using Squidex.Pipeline.Plugins;
using Squidex.Pipeline.Robots;
namespace Squidex.Config.Web
{
public static class WebServices
{
public static void AddMyMvc(this IServiceCollection services)
public static void AddMyMvc(this IServiceCollection services, IConfiguration config)
{
services.AddSingletonAs<FileCallbackResultExecutor>()
.AsSelf();
@ -47,7 +49,9 @@ namespace Squidex.Config.Web
options.Filters.Add<ETagFilter>();
options.Filters.Add<AppResolver>();
options.Filters.Add<MeasureResultFilter>();
}).AddMySerializers();
})
.AddMySerializers()
.AddMyPlugins(config);
services.AddCors();
services.AddRouting();

22
src/Squidex/Pipeline/Plugins/PluginExtensions.cs

@ -8,9 +8,11 @@
using System;
using System.Reflection;
using McMaster.NETCore.Plugins;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Extensions;
using Squidex.Infrastructure.Plugins;
namespace Squidex.Pipeline.Plugins
@ -19,14 +21,14 @@ namespace Squidex.Pipeline.Plugins
{
private static readonly Type[] SharedTypes = { typeof(IPlugin) };
public static void AddPlugins(IMvcBuilder mvcBuilder, IConfiguration configuration)
public static void AddMyPlugins(this IMvcBuilder mvcBuilder, IConfiguration configuration)
{
var pluginManager = new PluginManager();
var options = configuration.Get<PluginOptions>();
if (options.Plugins != null)
{
var pluginManager = new PluginManager();
foreach (var pluginPath in options.Plugins)
{
PluginLoader plugin = null;
@ -58,9 +60,19 @@ namespace Squidex.Pipeline.Plugins
pluginManager.Add(pluginAssembly);
}
}
mvcBuilder.Services.AddSingleton(pluginManager);
}
pluginManager.Add(SquidexExtensions.Assembly);
pluginManager.ConfigureServices(mvcBuilder.Services, configuration);
mvcBuilder.Services.AddSingleton(pluginManager);
}
public static void UsePlugins(this IApplicationBuilder app)
{
var pluginManager = app.ApplicationServices.GetRequiredService<PluginManager>();
pluginManager.Configure(app);
}
private static void AddParts(IMvcBuilder mvcBuilder, Assembly assembly)

5
src/Squidex/WebStartup.cs

@ -31,6 +31,7 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Diagnostics;
using Squidex.Infrastructure.Translations;
using Squidex.Pipeline;
using Squidex.Pipeline.Plugins;
using Squidex.Pipeline.Robots;
namespace Squidex
@ -62,7 +63,7 @@ namespace Squidex
services.AddMyInfrastructureServices(config);
services.AddMyLoggingServices(config);
services.AddMyMigrationServices();
services.AddMyMvc();
services.AddMyMvc(config);
services.AddMyRuleServices();
services.AddMySerializers();
services.AddMyStoreServices(config);
@ -124,6 +125,8 @@ namespace Squidex
app.ConfigureOrleansDashboard();
app.ConfigureIdentityServer();
app.ConfigureFrontend();
app.UsePlugins();
}
}
}

12
src/Squidex/app/features/rules/pages/rules/rule-element.component.html

@ -1,7 +1,11 @@
<ng-container *ngIf="isSmall; else large">
<div class="row no-gutters align-items-center small" *ngIf="element" [style.background]="element.iconColor" [sqxHoverBackground]="element.iconColor | sqxDarken:5">
<div class="col-auto small-icon" [style.background]="element.iconColor | sqxDarken:5">
<i class="svg-icon" [innerHtml]="element.iconImage | sqxSafeHtml"></i>
<i *ngIf="element.iconCode; else svgIcon" class="icon icon-{{element.iconCode}}"></i>
<ng-template #svgIcon>
<i class="svg-icon" [innerHtml]="element.iconImage | sqxSafeHtml"></i>
</ng-template>
</div>
<div class="col align-items-center">
<div class="small-text">
@ -14,7 +18,11 @@
<div class="row no-gutters large">
<div class="col-auto">
<div class="large-icon" [style.background]="element.iconColor | sqxDarken:5">
<div class="svg-icon" [innerHtml]="element.iconImage | sqxSafeHtml"></div>
<i *ngIf="element.iconCode; else svgIcon" class="icon icon-{{element.iconCode}}"></i>
<ng-template #svgIcon>
<i class="svg-icon" [innerHtml]="element.iconImage | sqxSafeHtml"></i>
</ng-template>
</div>
</div>
<div class="col">

9
src/Squidex/app/features/rules/pages/rules/rule-element.component.scss

@ -27,6 +27,10 @@
height: 3rem;
}
.icon {
font-size: 20px;
}
.svg-icon {
width: 20px;
}
@ -56,6 +60,7 @@
}
&-icon {
color: $color-dark-foreground;
display: inline-block;
margin-right: .5rem;
position: relative;
@ -63,6 +68,10 @@
line-height: 1px;
}
.icon {
font-size: 30px;
}
.svg-icon {
width: 30px;
}

8
src/Squidex/app/features/rules/pages/rules/rules-page.component.ts

@ -9,6 +9,7 @@ import { Component, OnInit } from '@angular/core';
import { onErrorResumeNext } from 'rxjs/operators';
import {
ALL_TRIGGERS,
AppsState,
DialogModel,
RuleDto,
@ -30,7 +31,7 @@ export class RulesPageComponent implements OnInit {
public wizardRule: RuleDto | null;
public ruleActions: { [name: string]: RuleElementDto };
public ruleTriggers: { [name: string]: RuleElementDto };
public ruleTriggers = ALL_TRIGGERS;
constructor(
public readonly appsState: AppsState,
@ -48,11 +49,6 @@ export class RulesPageComponent implements OnInit {
this.ruleActions = actions;
});
this.rulesService.getTriggers()
.subscribe(triggers => {
this.ruleTriggers = triggers;
});
this.schemasState.load().pipe(onErrorResumeNext()).subscribe();
}

41
src/Squidex/app/shared/services/rules.service.spec.ts

@ -77,45 +77,8 @@ describe('RulesService', () => {
});
expect(actions!).toEqual({
'action1': new RuleElementDto('display1', 'description1', '#111', '<svg path="1" />', 'link1'),
'action2': new RuleElementDto('display2', 'description2', '#222', '<svg path="2" />', 'link2')
});
}));
it('should make get request to get triggers',
inject([RulesService, HttpTestingController], (rulesService: RulesService, httpMock: HttpTestingController) => {
let triggers: { [ name: string ]: RuleElementDto };
rulesService.getTriggers().subscribe(result => {
triggers = result;
});
const req = httpMock.expectOne('http://service/p/api/rules/triggers');
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush({
'trigger2': {
display: 'display2',
description: 'description2',
iconColor: '#222',
iconImage: '<svg path="2" />',
readMore: 'link2'
},
'trigger1': {
display: 'display1',
description: 'description1',
iconColor: '#111',
iconImage: '<svg path="1" />',
readMore: 'link1'
}
});
expect(triggers!).toEqual({
'trigger1': new RuleElementDto('display1', 'description1', '#111', '<svg path="1" />', 'link1'),
'trigger2': new RuleElementDto('display2', 'description2', '#222', '<svg path="2" />', 'link2')
'action1': new RuleElementDto('display1', 'description1', '#111', '<svg path="1" />', null, 'link1'),
'action2': new RuleElementDto('display2', 'description2', '#222', '<svg path="2" />', null, 'link2')
});
}));

49
src/Squidex/app/shared/services/rules.service.ts

@ -21,12 +21,39 @@ import {
Versioned
} from '@app/framework';
export const ALL_TRIGGERS = {
'ContentChanged': {
description: 'For content changes like created, updated, published, unpublished...',
display: 'Content changed',
iconColor: '#3389ff',
iconCode: 'contents'
},
'AssetChanged': {
description: 'For asset changes like uploaded, updated (reuploaded), renamed, deleted...',
display: 'Asset changed',
iconColor: '#3389ff',
iconCode: 'assets'
},
'SchemaChanged': {
description: 'When a schema definition has been created, updated, published or deleted...',
display: 'Schema changed',
iconColor: '#3389ff',
iconCode: 'schemas'},
'Usage': {
description: 'When monthly API calls exceed a specified limit for one time a month...',
display: 'Usage exceeded',
iconColor: '#3389ff',
iconCode: 'dashboard'
}
};
export class RuleElementDto {
constructor(
public readonly display: string,
public readonly description: string,
public readonly iconColor: string,
public readonly iconImage: string,
public readonly iconCode: string | null,
public readonly readMore: string
) {
}
@ -120,27 +147,7 @@ export class RulesService {
for (let key of Object.keys(items).sort()) {
const value = items[key];
result[key] = new RuleElementDto(value.display, value.description, value.iconColor, value.iconImage, value.readMore);
}
return result;
}),
pretifyError('Failed to load Rules. Please reload.'));
}
public getTriggers(): Observable<{ [name: string]: RuleElementDto }> {
const url = this.apiUrl.buildUrl('api/rules/triggers');
return HTTP.getVersioned<any>(this.http, url).pipe(
map(response => {
const items: { [name: string]: any } = response.payload.body;
const result: { [name: string]: RuleElementDto } = {};
for (let key of Object.keys(items).sort()) {
const value = items[key];
result[key] = new RuleElementDto(value.display, value.description, value.iconColor, value.iconImage, value.readMore);
result[key] = new RuleElementDto(value.display, value.description, value.iconColor, value.iconImage, null, value.readMore);
}
return result;

Loading…
Cancel
Save