Browse Source

Fixes and simplified the angular integration. (#822)

* Fixes and simplified the angular integration.

* More fixes.
pull/823/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
4c31931851
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      backend/src/Squidex.Web/Pipeline/CachingManager.cs
  2. 56
      backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs
  3. 57
      backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs
  4. 61
      backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs
  5. 85
      backend/src/Squidex/Areas/Frontend/Startup.cs
  6. 4
      backend/src/Squidex/Areas/IdentityServer/Config/DynamicApplicationStore.cs
  7. 7
      backend/src/Squidex/Areas/IdentityServer/Controllers/Setup/SetupController.cs
  8. 75
      backend/src/Squidex/Areas/IdentityServer/Views/Setup/Webpack.cshtml
  9. 11
      backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml
  10. 13
      backend/src/Squidex/Squidex.csproj
  11. 1
      backend/src/Squidex/Startup.cs
  12. 15
      backend/src/Squidex/web.config
  13. 2
      backend/src/Squidex/wwwroot/client-callback-popup.html
  14. 2
      backend/src/Squidex/wwwroot/client-callback-silent.html
  15. 12
      frontend/.eslintrc.js
  16. 18
      frontend/app-config/helpers.js
  17. 275
      frontend/app-config/webpack.config.js
  18. 7
      frontend/app/index.html
  19. 4
      frontend/app/shared/services/auth.service.ts
  20. 193
      frontend/package-lock.json
  21. 5
      frontend/package.json

2
backend/src/Squidex.Web/Pipeline/CachingManager.cs

@ -146,7 +146,7 @@ namespace Squidex.Web.Pipeline
if (headers.Count > 0) if (headers.Count > 0)
{ {
response.Headers.Add(HeaderNames.Vary, new StringValues(headers.ToArray())); response.Headers[HeaderNames.Vary] = new StringValues(headers.ToArray());
} }
} }

56
backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs

@ -9,9 +9,11 @@ using System.Collections.Concurrent;
using System.Globalization; using System.Globalization;
using System.Net; using System.Net;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Squidex.Areas.Api.Controllers.UI; using Squidex.Areas.Api.Controllers.UI;
using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.History;
using Squidex.Infrastructure.Json;
using Squidex.Web; using Squidex.Web;
namespace Squidex.Areas.Frontend.Middlewares namespace Squidex.Areas.Frontend.Middlewares
@ -19,64 +21,52 @@ namespace Squidex.Areas.Frontend.Middlewares
public static class IndexExtensions public static class IndexExtensions
{ {
private static readonly ConcurrentDictionary<string, string> Texts = new ConcurrentDictionary<string, string>(); private static readonly ConcurrentDictionary<string, string> Texts = new ConcurrentDictionary<string, string>();
private static readonly JsonSerializer JsonSerializer = JsonSerializer.CreateDefault(new JsonSerializerSettings
public static bool IsIndex(this HttpContext context)
{
var path = context.Request.Path.Value;
return path == "/" || path?.EndsWith("/index.html", StringComparison.OrdinalIgnoreCase) == true;
}
public static bool IsHtmlPath(this HttpContext context)
{ {
return context.Request.Path.Value?.EndsWith(".html", StringComparison.OrdinalIgnoreCase) == true; ContractResolver = new CamelCasePropertyNamesContractResolver()
} });
public static bool IsNotModified(this HttpResponse response) public static bool IsIndex(this HttpContext context)
{ {
return response.StatusCode == (int)HttpStatusCode.NotModified; return context.Request.Path.StartsWithSegments("/index.html", StringComparison.OrdinalIgnoreCase);
} }
public static string AdjustBase(this string html, HttpContext httpContext) public static string AddOptions(this string html, HttpContext httpContext)
{ {
if (httpContext.Request.PathBase != null) var scripts = new List<string>
{ {
html = html.Replace("<base href=\"/\">", $"<base href=\"{httpContext.Request.PathBase}/\">", StringComparison.OrdinalIgnoreCase); $"var texts = {GetText(CultureInfo.CurrentUICulture.Name)};"
} };
return html;
}
public static string AddOptions(this string html, HttpContext httpContext)
{
var uiOptions = httpContext.RequestServices.GetService<IOptions<MyUIOptions>>()?.Value; var uiOptions = httpContext.RequestServices.GetService<IOptions<MyUIOptions>>()?.Value;
if (uiOptions != null) if (uiOptions != null)
{ {
var json = JObject.FromObject(uiOptions, JsonSerializer);
var values = httpContext.RequestServices.GetService<ExposedValues>(); var values = httpContext.RequestServices.GetService<ExposedValues>();
if (values != null) if (values != null)
{ {
uiOptions.More["info"] = values.ToString(); json["more"] ??= new JObject();
json["more"]!["info"] = values.ToString();
} }
var notifo = httpContext.RequestServices!.GetRequiredService<IOptions<NotifoOptions>>(); var notifo = httpContext.RequestServices!.GetService<IOptions<NotifoOptions>>();
if (notifo.Value.IsConfigured()) if (notifo?.Value.IsConfigured() == true)
{ {
uiOptions.More["notifoApi"] = notifo.Value.ApiUrl; json["more"] ??= new JObject();
json["more"]!["notifoApi"] = notifo.Value.ApiUrl;
} }
uiOptions.More["culture"] = CultureInfo.CurrentUICulture.Name; uiOptions.More["culture"] = CultureInfo.CurrentUICulture.Name;
var jsonSerializer = httpContext.RequestServices.GetRequiredService<IJsonSerializer>(); scripts.Add($"var options = {json.ToString(Formatting.Indented)};");
var jsonOptions = jsonSerializer.Serialize(uiOptions, true);
var texts = GetText(CultureInfo.CurrentUICulture.Name);
html = html.Replace("<body>", $"<body>\n<script>\nvar options = {jsonOptions};\nvar texts = {texts};</script>", StringComparison.OrdinalIgnoreCase);
} }
html = html.Replace("<body>", $"<body>\n<script>{string.Join(Environment.NewLine, scripts)}</script>", StringComparison.OrdinalIgnoreCase);
return html; return html;
} }

57
backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs

@ -1,57 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Text;
namespace Squidex.Areas.Frontend.Middlewares
{
public sealed class IndexMiddleware
{
private readonly RequestDelegate next;
public IndexMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.IsHtmlPath() && !context.Response.IsNotModified())
{
var responseBuffer = new MemoryStream();
var responseBody = context.Response.Body;
context.Response.Body = responseBuffer;
await next(context);
if (!context.Response.IsNotModified())
{
context.Response.Body = responseBody;
var html = Encoding.UTF8.GetString(responseBuffer.ToArray());
html = html.AdjustBase(context);
if (context.IsIndex())
{
html = html.AddOptions(context);
}
context.Response.ContentLength = Encoding.UTF8.GetByteCount(html);
context.Response.Body = responseBody;
await context.Response.WriteAsync(html, context.RequestAborted);
}
}
else
{
await next(context);
}
}
}
}

61
backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs

@ -1,61 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Areas.Frontend.Middlewares
{
public sealed class WebpackMiddleware
{
private const string WebpackUrl = "https://localhost:3000/index.html";
private readonly RequestDelegate next;
public WebpackMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.IsIndex() && !context.Response.IsNotModified())
{
try
{
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true
};
using (var client = new HttpClient(handler))
{
var result = await client.GetAsync(WebpackUrl, context.RequestAborted);
context.Response.StatusCode = (int)result.StatusCode;
if (result.IsSuccessStatusCode)
{
var html = await result.Content.ReadAsStringAsync(context.RequestAborted);
html = html.AdjustBase(context);
await context.Response.WriteAsync(html, context.RequestAborted);
}
}
}
catch
{
context.Request.Path = "/identity-server/webpack";
await next(context);
}
}
else
{
await next(context);
}
}
}
}

85
backend/src/Squidex/Areas/Frontend/Startup.cs

@ -5,8 +5,10 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.FileProviders;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Squidex.Areas.Frontend.Middlewares; using Squidex.Areas.Frontend.Middlewares;
using Squidex.Hosting.Web;
using Squidex.Pipeline.Squid; using Squidex.Pipeline.Squid;
using Squidex.Web.Pipeline; using Squidex.Web.Pipeline;
@ -18,74 +20,73 @@ namespace Squidex.Areas.Frontend
{ {
var environment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>(); var environment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
app.Map("/squid.svg", builder => builder.UseMiddleware<SquidMiddleware>()); var fileProvider = environment.WebRootFileProvider;
app.UseMiddleware<NotifoMiddleware>(); if (environment.IsProduction())
var indexFile =
environment.IsProduction() ?
new PathString("/build/index.html") :
new PathString("/index.html");
app.Use((context, next) =>
{ {
if (context.Request.Path == "/client-callback-popup") fileProvider = new CompositeFileProvider(fileProvider,
{ new PhysicalFileProvider(Path.Combine(environment.WebRootPath, "build")));
context.Request.Path = new PathString("/client-callback-popup.html");
} app.Use((context, next) =>
else if (context.Request.Path == "/client-callback-silent")
{
context.Request.Path = new PathString("/client-callback-silent.html");
}
else if (!Path.HasExtension(context.Request.Path.Value))
{ {
context.Request.Path = indexFile; if (!Path.HasExtension(context.Request.Path.Value))
} {
context.Request.Path = new PathString("/index.html");
}
return next(); return next();
});
}
app.Map("/squid.svg", builder =>
{
builder.UseMiddleware<SquidMiddleware>();
}); });
app.UseWhen(x => x.Request.Path.StartsWithSegments(indexFile, StringComparison.Ordinal), builder => app.UseMiddleware<NotifoMiddleware>();
app.UseWhen(x => x.IsIndex(), builder =>
{ {
builder.UseMiddleware<SetupMiddleware>(); builder.UseMiddleware<SetupMiddleware>();
}); });
app.UseMiddleware<IndexMiddleware>(); app.UseHtmlTransform(new HtmlTransformOptions
{
Transform = (html, context) =>
{
if (context.IsIndex())
{
html = html.AddOptions(context);
}
app.ConfigureDev(); return new ValueTask<string>(html);
}
});
app.UseStaticFiles(new StaticFileOptions app.UseStaticFiles(new StaticFileOptions
{ {
OnPrepareResponse = context => OnPrepareResponse = context =>
{ {
var response = context.Context.Response; var response = context.Context.Response;
var responseHeaders = response.GetTypedHeaders();
if (!string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase)) if (!string.IsNullOrWhiteSpace(context.Context.Request.QueryString.ToString()))
{ {
responseHeaders.CacheControl = new CacheControlHeaderValue response.Headers[HeaderNames.CacheControl] = "max-age=5184000";
{
MaxAge = TimeSpan.FromDays(60)
};
} }
else else if (string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase))
{ {
responseHeaders.CacheControl = new CacheControlHeaderValue response.Headers[HeaderNames.CacheControl] = "no-cache";
{
NoCache = true
};
} }
} },
FileProvider = fileProvider
}); });
}
public static void ConfigureDev(this IApplicationBuilder app)
{
var environment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
if (environment.IsDevelopment()) if (environment.IsDevelopment())
{ {
app.UseMiddleware<WebpackMiddleware>(); app.UseSpa(builder =>
{
builder.UseProxyToSpaDevelopmentServer("https://localhost:3000");
});
} }
} }
} }

4
backend/src/Squidex/Areas/IdentityServer/Config/DynamicApplicationStore.cs

@ -155,8 +155,8 @@ namespace Squidex.Areas.IdentityServer.Config
RedirectUris = RedirectUris =
{ {
new Uri(urlGenerator.BuildUrl("login;")), new Uri(urlGenerator.BuildUrl("login;")),
new Uri(urlGenerator.BuildUrl("client-callback-silent", false)), new Uri(urlGenerator.BuildUrl("client-callback-silent.html", false)),
new Uri(urlGenerator.BuildUrl("client-callback-popup", false)) new Uri(urlGenerator.BuildUrl("client-callback-popup.html", false))
}, },
PostLogoutRedirectUris = PostLogoutRedirectUris =
{ {

7
backend/src/Squidex/Areas/IdentityServer/Controllers/Setup/SetupController.cs

@ -43,13 +43,6 @@ namespace Squidex.Areas.IdentityServer.Controllers.Setup
this.userService = userService; this.userService = userService;
} }
[HttpGet]
[Route("webpack/")]
public IActionResult Webpack()
{
return View();
}
[HttpGet] [HttpGet]
[Route("setup/")] [Route("setup/")]
public async Task<IActionResult> Setup() public async Task<IActionResult> Setup()

75
backend/src/Squidex/Areas/IdentityServer/Views/Setup/Webpack.cshtml

@ -1,75 +0,0 @@
@{
ViewBag.Title = T.Get("setup.webpack.title");
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@ViewBag.Title - @T.Get("common.product")</title>
<link href="@Url.RootContentUrl("~/styles/bootstrap.min.css")" rel="stylesheet">
<style>
body {
background: #f5f6f9;
padding-left: 0;
padding-top: 3.75rem;
}
.profile-container {
margin: 0 auto;
max-width: 40rem;
min-width: 10rem;
padding: 1rem 2rem;
}
.profile-logo {
height: 1.75rem;
position: absolute;
padding-left: 0;
padding-right: 0;
right: 1rem;
top: 1rem;
}
.profile-footer {
font-size: .8rem;
font-weight: normal;
margin-top: 2rem;
}
.card-body {
text-align: center;
}
</style>
</head>
<body class="profile">
<div class="profile-container">
<img class="profile-logo" alt="@T.Get("common.product")S" title="@T.Get("common.product")" src="@Url.RootContentUrl("~/images/logo.svg")" />
<div class="profile-card card">
<div class="profile-card-body card-body">
<img class="splash-image" src="@Url.RootContentUrl("~/squid.svg?title=OH%20DAMN&text=Please%20run%20webpack")" />
<h1 class="splash-h1">@T.Get("setup.webpack.headline")</h1>
<p>@T.Get("setup.webpack.text")</p>
<a href="https://docs.squidex.io/01-getting-started/contributing-and-developing/developing" target="_blank">@T.Get("common.documentation")</a>
</div>
</div>
<div class="profile-footer text-center mt-4 mb-2">
<small class="text-muted">
@T.Get("setup.madeBy")<br />@T.Get("setup.madeByCopyright")
</small>
</div>
</div>
</body>
</html>

11
backend/src/Squidex/Areas/IdentityServer/Views/_Layout.cshtml

@ -8,9 +8,7 @@
<title>@ViewBag.Title - @T.Get("common.product")</title> <title>@ViewBag.Title - @T.Get("common.product")</title>
<environment names="Production"> <link rel="stylesheet" asp-append-version="true" href="@Url.RootContentUrl("~/app.css")" />
<link rel="stylesheet" asp-append-version="true" href="@Url.RootContentUrl("~/build/app.css")" />
</environment>
@if (IsSectionDefined("header")) @if (IsSectionDefined("header"))
{ {
@ -19,7 +17,7 @@
</head> </head>
<body class="profile"> <body class="profile">
<div class="profile-container"> <div class="profile-container">
<img class="profile-logo" alt="@T.Get("common.product")S" title="@T.Get("common.product")" src="@Url.RootContentUrl("~/images/logo.svg")" /> <img class="profile-logo" alt="@T.Get("common.product")" title="@T.Get("common.product")" src="@Url.RootContentUrl("~/images/logo.svg")" />
<div class="profile-card card"> <div class="profile-card card">
<div class="profile-card-body card-body"> <div class="profile-card-body card-body">
@ -33,10 +31,5 @@
</small> </small>
</div> </div>
</div> </div>
<environment names="Development">
<script type="text/javascript" src="https://localhost:3000/shims.js"></script>
<script type="text/javascript" src="https://localhost:3000/app.js"></script>
</environment>
</body> </body>
</html> </html>

13
backend/src/Squidex/Squidex.csproj

@ -48,6 +48,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.1" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" /> <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.3.3" /> <PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.3.3" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.5" /> <PackageReference Include="Microsoft.Data.Edm" Version="5.8.5" />
@ -79,18 +80,23 @@
<PackageReference Include="Squidex.Assets.S3" Version="2.6.0" /> <PackageReference Include="Squidex.Assets.S3" Version="2.6.0" />
<PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" /> <PackageReference Include="Squidex.Caching.Orleans" Version="1.8.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="7.7.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="7.7.0" />
<PackageReference Include="Squidex.Hosting" Version="2.4.0" /> <PackageReference Include="Squidex.Hosting" Version="2.8.0" />
<PackageReference Include="Squidex.OpenIddict.MongoDb" Version="4.0.1-dev" /> <PackageReference Include="Squidex.OpenIddict.MongoDb" Version="4.0.1-dev" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Linq" Version="4.3.0" /> <PackageReference Include="System.Linq" Version="4.3.0" />
<PackageReference Include="System.Runtime" Version="4.3.1" /> <PackageReference Include="System.Runtime" Version="4.3.1" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.0" GeneratePathProperty="true" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<Target Name="CopySystemSecurityCryptographyPkcs" AfterTargets="Build">
<Copy SourceFiles="$(PkgSystem_Security_Cryptography_Pkcs)\lib\net6.0\System.Security.Cryptography.Pkcs.dll" DestinationFolder="$(OutDir)" />
</Target>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup> </ItemGroup>
@ -126,6 +132,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Areas\Frontend\Resources\" /> <Folder Include="Areas\Frontend\Resources\" />
<Folder Include="wwwroot\build\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -156,6 +163,4 @@
<PropertyGroup> <PropertyGroup>
<NoWarn>$(NoWarn);CS1591;1591;1573;1572;NU1605;IDE0060</NoWarn> <NoWarn>$(NoWarn);CS1591;1591;1573;1572;NU1605;IDE0060</NoWarn>
</PropertyGroup> </PropertyGroup>
<ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="https://json.schemastore.org/bamboo-spec.json" /></VisualStudio></ProjectExtensions>
</Project> </Project>

1
backend/src/Squidex/Startup.cs

@ -90,7 +90,6 @@ namespace Squidex
app.UseSquidexLocalCache(); app.UseSquidexLocalCache();
app.UseSquidexCors(); app.UseSquidexCors();
app.ConfigureDev();
app.ConfigureApi(); app.ConfigureApi();
app.ConfigurePortal(); app.ConfigurePortal();
app.ConfigureOrleansDashboard(); app.ConfigureOrleansDashboard();

15
backend/src/Squidex/web.config

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<location path="." inheritInChildApplications="false"> <system.webServer>
<system.webServer> <handlers>
<handlers> <remove name="aspNetCore" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers> </handlers>
<aspNetCore processPath="bin\Debug\net5.0\Squidex.exe" arguments="" stdoutLogEnabled="false" hostingModel="InProcess" /> <aspNetCore processPath="dotnet" arguments=".\bin\Debug\net6.0\Squidex.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
</system.webServer> </system.webServer>
</location>
</configuration> </configuration>

2
backend/src/Squidex/wwwroot/client-callback-popup.html

@ -4,7 +4,7 @@
<base href="/"> <base href="/">
</head> </head>
<body> <body>
<script src="./scripts/oidc-client.min.js"></script> <script src="scripts/oidc-client.min.js"></script>
<script> <script>
Oidc.Log.logger = console; Oidc.Log.logger = console;
Oidc.Log.logLevel = Oidc.Log.INFO; Oidc.Log.logLevel = Oidc.Log.INFO;

2
backend/src/Squidex/wwwroot/client-callback-silent.html

@ -4,7 +4,7 @@
<base href="/"> <base href="/">
</head> </head>
<body> <body>
<script src="./scripts/oidc-client.min.js"></script> <script src="scripts/oidc-client.min.js"></script>
<script> <script>
Oidc.Log.logger = console; Oidc.Log.logger = console;
Oidc.Log.logLevel = Oidc.Log.INFO; Oidc.Log.logLevel = Oidc.Log.INFO;

12
frontend/.eslintrc.js

@ -73,20 +73,16 @@ module.exports = {
"error", "error",
"always" "always"
], ],
"import/extensions": [
"error",
"never"
],
"import/extensions": "off",
"import/no-extraneous-dependencies": "off",
"import/no-useless-path-segments": "off",
"import/prefer-default-export": "off",
"arrow-body-style": "off", "arrow-body-style": "off",
"arrow-parens": "off", "arrow-parens": "off",
"class-methods-use-this": "off", "class-methods-use-this": "off",
"default-case": "off", "default-case": "off",
"function-paren-newline": "off", "function-paren-newline": "off",
"implicit-arrow-linebreak": "off", "implicit-arrow-linebreak": "off",
"import/extensions": "off",
"import/no-extraneous-dependencies": "off",
"import/no-useless-path-segments": "off",
"import/prefer-default-export": "off",
"linebreak-style": "off", "linebreak-style": "off",
"max-classes-per-file": "off", "max-classes-per-file": "off",
"max-len": "off", "max-len": "off",

18
frontend/app-config/helpers.js

@ -0,0 +1,18 @@
const path = require('path');
const appRoot = path.resolve(__dirname, '..');
function root() {
var newArgs = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [appRoot].concat(newArgs));
}
function isDevServer() {
return path.basename(require.main.filename) === 'webpack-dev-server.js';
}
module.exports = {
root,
isDevServer,
};

275
frontend/app-config/webpack.config.js

@ -1,19 +1,7 @@
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
/* eslint-disable global-require */ /* eslint-disable global-require */
const webpack = require('webpack'); const webpack = require('webpack');
const path = require('path'); const helpers = require('./helpers');
const appRoot = path.resolve(__dirname, '..');
function root() {
// eslint-disable-next-line prefer-rest-params
const newArgs = Array.prototype.slice.call(arguments, 0);
// eslint-disable-next-line prefer-spread
return path.join.apply(path, [appRoot].concat(newArgs));
}
const plugins = { const plugins = {
// https://github.com/webpack-contrib/mini-css-extract-plugin // https://github.com/webpack-contrib/mini-css-extract-plugin
MiniCssExtractPlugin: require('mini-css-extract-plugin'), MiniCssExtractPlugin: require('mini-css-extract-plugin'),
@ -46,7 +34,7 @@ const plugins = {
module.exports = function calculateConfig(env) { module.exports = function calculateConfig(env) {
const isProduction = env && env.production; const isProduction = env && env.production;
const isAnalyzing = isProduction && env.analyze; const isAnalyzing = isProduction && env.analyze;
const isDevServer = env.WEBPACK_SERVE; const isDevServer = helpers.isDevServer();
const isTestCoverage = env && env.coverage; const isTestCoverage = env && env.coverage;
const isTests = env && env.target === 'tests'; const isTests = env && env.target === 'tests';
@ -59,28 +47,49 @@ module.exports = function calculateConfig(env) {
mode: isProduction ? 'production' : 'development', mode: isProduction ? 'production' : 'development',
/* /*
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack. * Source map for Karma from the help of karma-sourcemap-loader & karma-webpack.
* *
* See: https://webpack.js.org/configuration/devtool/ * See: https://webpack.js.org/configuration/devtool/
*/ */
devtool: isProduction ? false : 'inline-source-map', devtool: isProduction ? false : 'inline-source-map',
output: {
/*
* The output directory as absolute path (required).
*
* See: https://webpack.js.org/configuration/output/#output-path
*/
path: helpers.root('/build/'),
/*
* The filename of non-entry chunks as relative path inside the output.path directory.
*
* See: https://webpack.js.org/configuration/output/#output-chunkfilename
*/
chunkFilename: '[id].[fullhash].chunk.js',
/*
* The filename for assets.
*/
assetModuleFilename: 'assets/[hash][ext][query]',
},
/* /*
* Options affecting the resolving of modules. * Options affecting the resolving of modules.
* *
* See: https://webpack.js.org/configuration/resolve/ * See: https://webpack.js.org/configuration/resolve/
*/ */
resolve: { resolve: {
/* /*
* An array of extensions that should be used to resolve modules. * An array of extensions that should be used to resolve modules.
* *
* See: https://webpack.js.org/configuration/resolve/#resolve-extensions * See: https://webpack.js.org/configuration/resolve/#resolve-extensions
*/ */
extensions: ['.ts', '.js', '.mjs', '.css', '.scss'], extensions: ['.ts', '.js', '.mjs', '.css', '.scss'],
modules: [ modules: [
root('app'), helpers.root('app'),
root('app', 'theme'), helpers.root('app', 'theme'),
root('node_modules'), helpers.root('node_modules'),
], ],
plugins: [ plugins: [
@ -91,21 +100,17 @@ module.exports = function calculateConfig(env) {
}, },
/* /*
* Options affecting the normal modules. * Options affecting the normal modules.
* *
* See: https://webpack.js.org/configuration/module/ * See: https://webpack.js.org/configuration/module/
*/ */
module: { module: {
/* /*
* An array of Rules which are matched to requests when modules are created. * An array of Rules which are matched to requests when modules are created.
* *
* See: https://webpack.js.org/configuration/module/#module-rules * See: https://webpack.js.org/configuration/module/#module-rules
*/ */
rules: [{ rules: [{
test: /\.mjs$/,
type: 'javascript/auto',
include: [/node_modules/],
}, {
// Mark files inside `@angular/core` as using SystemJS style dynamic imports. // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/, test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true }, parser: { system: true },
@ -152,15 +157,35 @@ module.exports = function calculateConfig(env) {
loader: 'sass-loader', loader: 'sass-loader',
options: { options: {
additionalData: ` additionalData: `
@import '_vars'; @import '_vars';
@import '_mixins'; @import '_mixins';
`, `,
sassOptions: { sassOptions: {
includePaths: [root('app', 'theme')], includePaths: [helpers.root('app', 'theme')],
}, },
}, },
}], }],
exclude: root('app', 'theme'), exclude: helpers.root('app', 'theme'),
}, {
test: /\.scss$/,
/*
* Extract the content from a bundle to a file.
*
* See: https://github.com/webpack-contrib/extract-text-webpack-plugin
*/
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
}, {
loader: 'postcss-loader',
}, {
loader: 'sass-loader',
}],
/*
* Do not include component styles.
*/
include: helpers.root('app', 'theme'),
}], }],
}, },
@ -174,11 +199,11 @@ module.exports = function calculateConfig(env) {
}), }),
/* /*
* Always replace the context for the System.import in angular/core to prevent warnings. * Always replace the context for the System.import in angular/core to prevent warnings.
*/ */
new webpack.ContextReplacementPlugin( new webpack.ContextReplacementPlugin(
/\@angular(\\|\/)core(\\|\/)/, /\@angular(\\|\/)core(\\|\/)/,
root('./app', '$_lazy_route_resources'), helpers.root('./app', '$_lazy_route_resources'),
{}, {},
), ),
@ -192,10 +217,10 @@ module.exports = function calculateConfig(env) {
}), }),
/* /*
* Puts each bundle into a file and appends the hash of the file to the path. * Puts each bundle into a file and appends the hash of the file to the path.
* *
* See: https://github.com/webpack-contrib/mini-css-extract-plugin * See: https://github.com/webpack-contrib/mini-css-extract-plugin
*/ */
new plugins.MiniCssExtractPlugin({ new plugins.MiniCssExtractPlugin({
filename: '[name].css', filename: '[name].css',
}), }),
@ -204,11 +229,11 @@ module.exports = function calculateConfig(env) {
options: { options: {
htmlLoader: { htmlLoader: {
/* /*
* Define the root for images, so that we can use absolute urls. * Define the root for images, so that we can use absolute urls.
* *
* See: https://github.com/webpack/html-loader#Advanced_Options * See: https://github.com/webpack/html-loader#Advanced_Options
*/ */
root: root('app', 'images'), root: helpers.root('app', 'images'),
}, },
context: '/', context: '/',
}, },
@ -219,10 +244,10 @@ module.exports = function calculateConfig(env) {
}), }),
/* /*
* Detect circular dependencies in app. * Detect circular dependencies in app.
* *
* See: https://github.com/aackerman/circular-dependency-plugin * See: https://github.com/aackerman/circular-dependency-plugin
*/ */
new plugins.CircularDependencyPlugin({ new plugins.CircularDependencyPlugin({
exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/, exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/,
// Add errors to webpack instead of warnings // Add errors to webpack instead of warnings
@ -230,8 +255,8 @@ module.exports = function calculateConfig(env) {
}), }),
/* /*
* Copy lazy loaded libraries to output. * Copy lazy loaded libraries to output.
*/ */
new plugins.CopyPlugin({ new plugins.CopyPlugin({
patterns: [ patterns: [
{ from: './node_modules/simplemde/dist', to: 'dependencies/simplemde' }, { from: './node_modules/simplemde/dist', to: 'dependencies/simplemde' },
@ -279,70 +304,30 @@ module.exports = function calculateConfig(env) {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
}, },
historyApiFallback: true, historyApiFallback: true,
}, },
}; };
if (!isTests) { if (!isTests) {
/* /*
* The entry point for the bundle. Our Angular app. * The entry point for the bundle. Our Angular app.
* *
* See: https://webpack.js.org/configuration/entry-context/ * See: https://webpack.js.org/configuration/entry-context/
*/ */
config.entry = { config.entry = {
shims: './app/shims.ts', shims: './app/shims.ts',
style: './app/style.js', style: './app/style.js',
app: './app/app.ts', app: './app/app.ts',
}; };
if (isProduction) {
config.output = {
/*
* The output directory as absolute path (required).
*
* See: https://webpack.js.org/configuration/output/#output-path
*/
path: root('/build/'),
publicPath: './build/',
/*
* Specifies the name of each output file on disk.
*
* See: https://webpack.js.org/configuration/output/#output-filename
*/
filename: '[name].js',
/*
* The filename of non-entry chunks as relative path inside the output.path directory.
*
* See: https://webpack.js.org/configuration/output/#output-chunkfilename
*/
chunkFilename: '[id].[fullhash].chunk.js',
/*
* The filename for assets.
*/
assetModuleFilename: 'assets/[hash][ext][query]',
};
} else {
config.output = {
filename: '[name].js',
/*
* Set the public path, because we are running the website from another port (5000).
*/
publicPath: 'https://localhost:3000/',
};
}
config.plugins.push( config.plugins.push(
new plugins.HtmlWebpackPlugin({ new plugins.HtmlWebpackPlugin({
filename: 'index.html', filename: 'index.html',
hash: true, hash: true,
chunks: ['shims', 'app'], chunks: ['shims', 'app'],
chunksSortMode: 'manual', chunksSortMode: 'manual',
template: root('app', 'index.html'), template: helpers.root('app', 'index.html'),
}), }),
); );
@ -352,10 +337,17 @@ module.exports = function calculateConfig(env) {
hash: true, hash: true,
chunks: ['style'], chunks: ['style'],
chunksSortMode: 'none', chunksSortMode: 'none',
template: root('app', '_theme.html'), template: helpers.root('app', '_theme.html'),
}), }),
); );
/*
* Specifies the name of each output file on disk.
*
* See: https://webpack.js.org/configuration/output/#output-filename
*/
config.output.filename = '[name].js';
if (isProduction) { if (isProduction) {
config.plugins.push( config.plugins.push(
new plugins.ESLintPlugin({ new plugins.ESLintPlugin({
@ -398,6 +390,23 @@ module.exports = function calculateConfig(env) {
}, },
}], }],
}); });
config.module.rules.push({
test: /\.m?js$/,
use: [{
loader: 'babel-loader',
options: {
plugins: ['@angular/compiler-cli/linker/babel'],
compact: false,
cacheDirectory: true,
},
}],
});
} else {
config.module.rules.push({
test: /\.mjs$/,
type: 'javascript/auto',
include: [/node_modules/],
});
} }
if (isTestCoverage) { if (isTestCoverage) {
@ -432,48 +441,6 @@ module.exports = function calculateConfig(env) {
}); });
} }
if (isProduction) {
config.module.rules.push({
test: /\.scss$/,
/*
* Extract the content from a bundle to a file.
*
* See: https://github.com/webpack-contrib/extract-text-webpack-plugin
*/
use: [
plugins.MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
}, {
loader: 'postcss-loader',
}, {
loader: 'sass-loader',
}],
/*
* Do not include component styles.
*/
include: root('app', 'theme'),
});
} else {
config.module.rules.push({
test: /\.scss$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader',
}, {
loader: 'postcss-loader',
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
},
}],
// Do not include component styles.
include: root('app', 'theme'),
});
}
if (isAnalyzing) { if (isAnalyzing) {
config.plugins.push(new plugins.BundleAnalyzerPlugin()); config.plugins.push(new plugins.BundleAnalyzerPlugin());
} }

7
frontend/app/index.html

@ -20,9 +20,9 @@
</style> </style>
</noscript> </noscript>
<link rel="stylesheet" type="text/css" href="./scripts/outdatedbrowser/outdatedbrowser.min.css"> <link rel="stylesheet" type="text/css" href="scripts/outdatedbrowser/outdatedbrowser.min.css">
<script src="./scripts/outdatedbrowser/outdatedbrowser.min.js"></script> <script src="scripts/outdatedbrowser/outdatedbrowser.min.js"></script>
<script> <script>
function addLoadEvent(callback) { function addLoadEvent(callback) {
var oldOnload = window.onload; var oldOnload = window.onload;
@ -42,7 +42,8 @@
addLoadEvent(function () { addLoadEvent(function () {
outdatedBrowser({ outdatedBrowser({
lowerThan: 'object-fit', lowerThan: 'object-fit',
languagePath: './scripts/outdatedbrowser/lang/en.html' language: 'en',
languagePath: 'scripts/outdatedbrowser/lang/en.html'
}); });
}); });
</script> </script>

4
frontend/app/shared/services/auth.service.ts

@ -102,8 +102,8 @@ export class AuthService {
response_type: 'code', response_type: 'code',
redirect_uri: apiUrl.buildUrl('login;'), redirect_uri: apiUrl.buildUrl('login;'),
post_logout_redirect_uri: apiUrl.buildUrl('logout'), post_logout_redirect_uri: apiUrl.buildUrl('logout'),
silent_redirect_uri: apiUrl.buildUrl('client-callback-silent'), silent_redirect_uri: apiUrl.buildUrl('client-callback-silent.html'),
popup_redirect_uri: apiUrl.buildUrl('client-callback-popup'), popup_redirect_uri: apiUrl.buildUrl('client-callback-popup.html'),
authority: apiUrl.buildUrl('identity-server/'), authority: apiUrl.buildUrl('identity-server/'),
userStore: new WebStorageStateStore({ store: window.localStorage || window.sessionStorage }), userStore: new WebStorageStateStore({ store: window.localStorage || window.sessionStorage }),
automaticSilentRenew: true, automaticSilentRenew: true,

193
frontend/package-lock.json

@ -66,7 +66,7 @@
"@angular-devkit/build-optimizer": "0.1301.2", "@angular-devkit/build-optimizer": "0.1301.2",
"@angular/cli": "^13.1.2", "@angular/cli": "^13.1.2",
"@angular/compiler": "13.1.1", "@angular/compiler": "13.1.1",
"@angular/compiler-cli": "13.1.1", "@angular/compiler-cli": "^13.1.1",
"@jsdevtools/coverage-istanbul-loader": "^3.0.5", "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
"@ngtools/webpack": "13.1.2", "@ngtools/webpack": "13.1.2",
"@types/codemirror": "0.0.108", "@types/codemirror": "0.0.108",
@ -84,6 +84,7 @@
"@types/ws": "8.2.2", "@types/ws": "8.2.2",
"@typescript-eslint/eslint-plugin": "5.8.1", "@typescript-eslint/eslint-plugin": "5.8.1",
"@typescript-eslint/parser": "5.8.1", "@typescript-eslint/parser": "5.8.1",
"babel-loader": "^8.2.3",
"browserslist": "4.19.1", "browserslist": "4.19.1",
"caniuse-lite": "1.0.30001294", "caniuse-lite": "1.0.30001294",
"circular-dependency-plugin": "5.2.2", "circular-dependency-plugin": "5.2.2",
@ -3079,6 +3080,69 @@
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
} }
}, },
"node_modules/babel-loader": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz",
"integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==",
"dev": true,
"dependencies": {
"find-cache-dir": "^3.3.1",
"loader-utils": "^1.4.0",
"make-dir": "^3.1.0",
"schema-utils": "^2.6.5"
},
"engines": {
"node": ">= 8.9"
},
"peerDependencies": {
"@babel/core": "^7.0.0",
"webpack": ">=2"
}
},
"node_modules/babel-loader/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/babel-loader/node_modules/loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"dev": true,
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/babel-loader/node_modules/schema-utils": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 8.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/babel-polyfill": { "node_modules/babel-polyfill": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
@ -3851,6 +3915,12 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"node_modules/component-emitter": { "node_modules/component-emitter": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
@ -6360,6 +6430,23 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true "dev": true
}, },
"node_modules/find-cache-dir": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
"integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
"dev": true,
"dependencies": {
"commondir": "^1.0.1",
"make-dir": "^3.0.2",
"pkg-dir": "^4.1.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
}
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@ -10409,6 +10496,18 @@
"pkcs7": "bin/cli.js" "pkcs7": "bin/cli.js"
} }
}, },
"node_modules/pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"dependencies": {
"find-up": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/portfinder": { "node_modules/portfinder": {
"version": "1.0.28", "version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@ -14609,18 +14708,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/webpack-cli/node_modules/pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"dependencies": {
"find-up": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/webpack-cli/node_modules/resolve-cwd": { "node_modules/webpack-cli/node_modules/resolve-cwd": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
@ -17412,6 +17499,51 @@
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
} }
}, },
"babel-loader": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz",
"integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==",
"dev": true,
"requires": {
"find-cache-dir": "^3.3.1",
"loader-utils": "^1.4.0",
"make-dir": "^3.1.0",
"schema-utils": "^2.6.5"
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
},
"schema-utils": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"ajv-keywords": "^3.5.2"
}
}
}
},
"babel-polyfill": { "babel-polyfill": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
@ -18030,6 +18162,12 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"component-emitter": { "component-emitter": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
@ -19957,6 +20095,17 @@
} }
} }
}, },
"find-cache-dir": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
"integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^3.0.2",
"pkg-dir": "^4.1.0"
}
},
"find-up": { "find-up": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@ -22970,6 +23119,15 @@
"@babel/runtime": "^7.5.5" "@babel/runtime": "^7.5.5"
} }
}, },
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
},
"portfinder": { "portfinder": {
"version": "1.0.28", "version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@ -26012,15 +26170,6 @@
"path-key": "^3.0.0" "path-key": "^3.0.0"
} }
}, },
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
},
"resolve-cwd": { "resolve-cwd": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",

5
frontend/package.json

@ -5,7 +5,7 @@
"license": "MIT", "license": "MIT",
"repository": "https://github.com/SebastianStehle/Squidex", "repository": "https://github.com/SebastianStehle/Squidex",
"scripts": { "scripts": {
"start": "webpack serve --config app-config/webpack.config.js --port 3000 --hot --server-type https --https-pfx ../dev/squidex-dev.pfx --https-passphrase password --env WEBPACK_SERVE", "start": "webpack serve --config app-config/webpack.config.js --port 3000 --hot --server-type https --server-options-pfx ../dev/squidex-dev.pfx --server-options-passphrase password --env WEBPACK_SERVE",
"test": "karma start", "test": "karma start",
"test:coverage": "karma start karma.coverage.conf.js", "test:coverage": "karma start karma.coverage.conf.js",
"test:clean": "rimraf _test-output", "test:clean": "rimraf _test-output",
@ -74,7 +74,7 @@
"@angular-devkit/build-optimizer": "0.1301.2", "@angular-devkit/build-optimizer": "0.1301.2",
"@angular/cli": "^13.1.2", "@angular/cli": "^13.1.2",
"@angular/compiler": "13.1.1", "@angular/compiler": "13.1.1",
"@angular/compiler-cli": "13.1.1", "@angular/compiler-cli": "^13.1.1",
"@jsdevtools/coverage-istanbul-loader": "^3.0.5", "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
"@ngtools/webpack": "13.1.2", "@ngtools/webpack": "13.1.2",
"@types/codemirror": "0.0.108", "@types/codemirror": "0.0.108",
@ -92,6 +92,7 @@
"@types/ws": "8.2.2", "@types/ws": "8.2.2",
"@typescript-eslint/eslint-plugin": "5.8.1", "@typescript-eslint/eslint-plugin": "5.8.1",
"@typescript-eslint/parser": "5.8.1", "@typescript-eslint/parser": "5.8.1",
"babel-loader": "^8.2.3",
"browserslist": "4.19.1", "browserslist": "4.19.1",
"caniuse-lite": "1.0.30001294", "caniuse-lite": "1.0.30001294",
"circular-dependency-plugin": "5.2.2", "circular-dependency-plugin": "5.2.2",

Loading…
Cancel
Save