();
16 | builder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=CoalesceDb;Trusted_Connection=True;");
17 | return new AppDbContext(builder.Options);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/playground/Coalesce.Domain/ZipCode.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel.DataAnnotations;
5 | using System.ComponentModel.DataAnnotations.Schema;
6 | using System.Text;
7 |
8 | namespace Coalesce.Domain
9 | {
10 | public class ZipCode
11 | {
12 | [Key]
13 | [DatabaseGenerated(DatabaseGeneratedOption.None)]
14 | [ListText]
15 | public string Zip { get; set; } = null!;
16 |
17 | public string State { get; set; } = null!;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules\\typescript\\lib"
3 | }
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Error";
3 | }
4 |
5 | Error.
6 | An error occurred while processing your request.
7 |
8 | @if (!string.IsNullOrEmpty((string?)ViewData["RequestId"]))
9 | {
10 |
11 | Request ID: @ViewData["RequestId"]
12 |
13 | }
14 |
15 | Development Mode
16 |
17 | Swapping to Development environment will display more detailed information about the error that occurred.
18 |
19 |
20 | Development environment should not be enabled in deployed applications , as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development , and restarting the application.
21 |
22 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - VuePlayground
7 |
8 |
9 |
10 |
11 | @RenderBody()
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Coalesce.Web.Vue
2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
3 | @addTagHelper *, Microsoft.AspNetCore.SpaServices
4 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "Debug": {
5 | "LogLevel": {
6 | "Default": "Debug",
7 | "System": "Information",
8 | "Microsoft": "Information"
9 | }
10 | },
11 | "Console": {
12 | "LogLevel": {
13 | "Default": "Debug",
14 | "System": "Information",
15 | "Microsoft": "Information"
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=CoalesceDb;Trusted_Connection=True;"
4 | },
5 |
6 | "Logging": {
7 | "IncludeScopes": false,
8 | "Debug": {
9 | "LogLevel": {
10 | "Default": "Warning"
11 | }
12 | },
13 | "Console": {
14 | "LogLevel": {
15 | "Default": "Warning"
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MyAppName
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IntelliTect/Coalesce/bbbb55fd51a58355ab296730e7b0f40f4f543ca6/playground/Coalesce.Web.Vue2/public/favicon.ico
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/src/css/site.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 | .v-input--is-readonly {
4 | fieldset {
5 | border-style: dashed !important;
6 | }
7 |
8 | .v-input--switch__track {
9 | background: #e6e6e6;
10 | border: 1px dashed black;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/src/vue-shim.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.vue" {
2 | import VueConstructor from "vue";
3 | export default VueConstructor;
4 | }
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue2/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "warning",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "rules": {
7 | "quotemark": [true, "single"],
8 | "indent": [true, "spaces", 2],
9 | "interface-name": false,
10 | "ordered-imports": false,
11 | "object-literal-sort-keys": false,
12 | "no-consecutive-blank-lines": false
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended',
9 | '@vue/eslint-config-typescript',
10 | ],
11 | rules: {
12 | 'vue/multi-word-component-names': 'off',
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnPaste": false,
3 | "editor.formatOnSave": true,
4 | "editor.formatOnType": true,
5 | "editor.defaultFormatter": "esbenp.prettier-vscode",
6 | "typescript.tsdk": "node_modules\\typescript\\lib",
7 | "dotnet.defaultSolution": "Coalesce.Web.Vue3.sln"
8 | }
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/Coalesce.Web.Vue3.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | InProcess
6 |
7 | enable
8 | true
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Error";
3 | }
4 |
5 | Error.
6 | An error occurred while processing your request.
7 |
8 | @if (!string.IsNullOrEmpty((string?)ViewData["RequestId"]))
9 | {
10 |
11 | Request ID: @ViewData["RequestId"]
12 |
13 | }
14 |
15 | Development Mode
16 |
17 | Swapping to Development environment will display more detailed information about the error that occurred.
18 |
19 |
20 | Development environment should not be enabled in deployed applications , as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development , and restarting the application.
21 |
22 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - VuePlayground
7 |
8 |
9 |
10 |
11 | @RenderBody()
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Coalesce.Web.Vue
2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
3 | @addTagHelper *, Microsoft.AspNetCore.SpaServices
4 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "Debug": {
5 | "LogLevel": {
6 | "Default": "Debug",
7 | "System": "Information",
8 | "Microsoft": "Information"
9 | }
10 | },
11 | "Console": {
12 | "LogLevel": {
13 | "Default": "Debug",
14 | "System": "Information",
15 | "Microsoft": "Information"
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=CoalesceDb;Trusted_Connection=True;"
4 | },
5 |
6 | "Logging": {
7 | "IncludeScopes": false,
8 | "Debug": {
9 | "LogLevel": {
10 | "Default": "Warning"
11 | }
12 | },
13 | "Console": {
14 | "LogLevel": {
15 | "Default": "Warning"
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Vuetify 3 Vite Preview
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IntelliTect/Coalesce/bbbb55fd51a58355ab296730e7b0f40f4f543ca6/playground/Coalesce.Web.Vue3/public/favicon.ico
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 | Artboard 46
2 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/src/css/site.scss:
--------------------------------------------------------------------------------
1 |
2 | @media (max-width: 767px) {
3 | /* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
4 | body {
5 | padding-top: 50px;
6 | }
7 | }
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | declare module "*.vue" {
5 | import type { DefineComponent } from "vue";
6 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
7 | const component: DefineComponent<{}, {}, any>;
8 | export default component;
9 | }
10 |
11 | // declare module 'vuetify'
12 | // declare module 'vuetify/lib/components'
13 | // declare module 'vuetify/lib/directives'
14 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/src/examples/c-select-many-to-many/styling.vue:
--------------------------------------------------------------------------------
1 |
2 | c-select slots
3 |
4 |
5 |
6 |
7 | v-input
8 |
9 |
10 | v-field
11 |
12 |
13 | {{ item.name }}
14 |
15 |
16 | {{ item.name }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
--------------------------------------------------------------------------------
/playground/Coalesce.Web.Vue3/src/worker.ts:
--------------------------------------------------------------------------------
1 | console.log('hello from worker');
2 |
--------------------------------------------------------------------------------
/playground/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 12.0
4 | false
5 | true
6 |
7 |
8 | false
9 |
10 |
11 |
12 |
13 | all
14 | analyzers
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Cli.Common.props:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | .NET Core command-line tooling for IntelliTect.Coalesce code generation
8 | Exe
9 |
10 |
11 | LatestMinor
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0;net9.0
4 |
5 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging.Tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Xunit;
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/DefaultAuditOperationContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.EntityFrameworkCore.ChangeTracking;
3 | using System.Security.Claims;
4 |
5 | namespace IntelliTect.Coalesce.AuditLogging;
6 |
7 | public class DefaultAuditOperationContext : IAuditOperationContext
8 | where TAuditLog : DefaultAuditLog
9 | {
10 | public DefaultAuditOperationContext(IHttpContextAccessor httpContextAccessor)
11 | {
12 | HttpContextAccessor = httpContextAccessor;
13 | }
14 |
15 | private IHttpContextAccessor HttpContextAccessor { get; }
16 |
17 | public HttpContext? HttpContext => HttpContextAccessor.HttpContext;
18 |
19 | public ClaimsPrincipal? User => HttpContext?.User;
20 |
21 | public virtual void Populate(TAuditLog auditEntry, EntityEntry changedEntity)
22 | {
23 | // read only once from the underlying AsyncLocal for perf:
24 | var context = HttpContext;
25 |
26 | auditEntry.ClientIp = context?.Connection?.RemoteIpAddress?.ToString();
27 | auditEntry.Referrer = context?.Request?.GetTypedHeaders()?.Referer?.PathAndQuery;
28 | auditEntry.Endpoint = context?.Request?.Path;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/IAuditLogDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace IntelliTect.Coalesce.AuditLogging;
4 |
5 | ///
6 | /// An interface representing the s that hold the data produced by Coalesce's audit logging features.
7 | ///
8 | /// The type of entity representing a change to an entity. You are expected to make your own implementation of this entity in your application code, inheriting from or .
9 | ///
10 | public interface IAuditLogDbContext
11 | where TAuditLog : class, IAuditLog
12 | {
13 | DbSet AuditLogs { get; }
14 |
15 | DbSet AuditLogProperties { get; }
16 |
17 | ///
18 | /// When , audit operations on the will be skipped.
19 | ///
20 | bool SuppressAudit => false;
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/IAuditOperationContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.ChangeTracking;
2 |
3 | namespace IntelliTect.Coalesce.AuditLogging;
4 |
5 | ///
6 | /// Defines a service that can populate additional fields on the given before it is persisted to the database. Declare the implementation of this service by calling .
7 | ///
8 | public interface IAuditOperationContext : IAuditOperationContext
9 | {
10 | ///
11 | void Populate(TAuditLog auditEntry, EntityEntry changedEntity);
12 |
13 | void IAuditOperationContext.Populate(IAuditLog auditEntry, EntityEntry changedEntity)
14 | {
15 | Populate((TAuditLog) auditEntry, changedEntity);
16 | }
17 | }
18 |
19 | public interface IAuditOperationContext
20 | {
21 | ///
22 | /// A hook that may be overridden to populate additional contextual information on an audit entry.
23 | ///
24 | void Populate(IAuditLog auditEntry, EntityEntry changedEntity);
25 | }
26 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/IntelliTect.Coalesce.AuditLogging.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/Models/AuditEntry.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.AuditLogging.Internal;
2 | using Microsoft.EntityFrameworkCore.ChangeTracking;
3 | using System.Collections.Generic;
4 |
5 | namespace IntelliTect.Coalesce.AuditLogging;
6 |
7 | public class AuditEntry
8 | {
9 | public required EntityEntry Entry { get; init; }
10 |
11 | public required CoalesceAudit Parent { get; init; }
12 |
13 | public required AuditEntryState State { get; set; }
14 |
15 | public List Properties { get; set; } = new();
16 |
17 | public object Entity => Entry.Entity;
18 | }
19 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/Models/AuditEntryProperty.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.ChangeTracking;
2 |
3 | namespace IntelliTect.Coalesce.AuditLogging;
4 |
5 | public class AuditEntryProperty
6 | {
7 | public required PropertyEntry PropertyEntry { get; init; }
8 |
9 | public required AuditEntry Parent { get; init; }
10 |
11 | public string PropertyName => PropertyEntry.Metadata.Name;
12 |
13 | public bool IsKey => PropertyEntry.Metadata.IsKey();
14 |
15 | public object? NewValue { get; set; }
16 | public string? NewValueDescription { get; set; }
17 |
18 | public string? NewValueFormatted => Parent.State == AuditEntryState.EntityDeleted
19 | ? null
20 | : Parent.Parent.Configuration.GetFormattedValue(PropertyEntry, NewValue);
21 |
22 | public object? OldValue { get; set; }
23 | public string? OldValueDescription { get; set; }
24 |
25 | public string? OldValueFormatted => Parent.State == AuditEntryState.EntityAdded
26 | ? null
27 | : Parent.Parent.Configuration.GetFormattedValue(PropertyEntry, OldValue);
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.AuditLogging/Models/AuditEntryState.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.AuditLogging;
2 |
3 | ///
4 | /// Represents the kind of operation that was performed on an entity.
5 | ///
6 | public enum AuditEntryState : byte
7 | {
8 | ///
9 | /// The entity was added
10 | ///
11 | EntityAdded = 0,
12 |
13 | ///
14 | /// The entity was deleted
15 | ///
16 | EntityDeleted = 1,
17 |
18 | ///
19 | /// The entity was modified
20 | ///
21 | EntityModified = 2
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Api/IntelliTect.Coalesce.CodeGeneration.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shared API code generation for IntelliTect.Coalesce
5 | AnyCPU
6 | Library
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Api/MvcCodeGenerationExtensions.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using IntelliTect.Coalesce.TypeDefinition;
3 | using IntelliTect.Coalesce.Utilities;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 |
9 | namespace IntelliTect.Coalesce.CodeGeneration.Api
10 | {
11 | public static class MvcCodeGenerationExtensions
12 | {
13 | public static string MvcAnnotation(this SecurityPermission permission)
14 | {
15 | if (permission.NoAccess) throw new InvalidOperationException($"Cannot emit an annotation for security level {SecurityPermissionLevels.DenyAll}");
16 | if (permission.AllowAnonymous) return "[AllowAnonymous]";
17 | if (permission.HasRoles) return string.Concat(permission.RoleLists.Select(rl =>
18 | $"[Authorize(Roles={string.Join(",", rl).QuotedStringLiteralForCSharp()})]"));
19 | return "[Authorize]";
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:27477/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "IntelliTect.Coalesce.CodeGeneration.Api": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:27478/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Tests/.gitignore:
--------------------------------------------------------------------------------
1 | out
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Vue/Generators/Controllers.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.CodeGeneration.Api.BaseGenerators;
2 | using IntelliTect.Coalesce.CodeGeneration.Api.Generators;
3 | using IntelliTect.Coalesce.CodeGeneration.Generation;
4 | using IntelliTect.Coalesce.TypeDefinition;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text;
10 |
11 | namespace IntelliTect.Coalesce.CodeGeneration.Vue.Generators
12 | {
13 | public class Controllers : IntelliTect.Coalesce.CodeGeneration.Api.Generators.Controllers
14 | {
15 | public Controllers(CompositeGeneratorServices services) : base(services) { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Vue/IntelliTect.Coalesce.CodeGeneration.Vue.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Vue.js code generation for IntelliTect.Coalesce
5 | AnyCPU
6 | Library
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration.Vue/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:28570/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "IntelliTect.Coalesce.CodeGeneration.Vue": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:28571/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Analysis/Base/IProjectContextFactory.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.CodeGeneration.Configuration;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace IntelliTect.Coalesce.CodeGeneration.Analysis.Base
8 | {
9 | public interface IProjectContextFactory
10 | {
11 | ProjectContext CreateContext(ProjectConfiguration projectConfig, bool restore = false);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Analysis/Base/TypeLocator.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace IntelliTect.Coalesce.CodeGeneration.Analysis.Base
8 | {
9 | public abstract class TypeLocator
10 | {
11 | public abstract TypeViewModel FindType(string typeName, bool throwWhenNotFound = true);
12 |
13 | public abstract IEnumerable FindDerivedTypes(string typeName, bool throwWhenNotFound = true);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Analysis/MsBuild/Targets/Imports.targets:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | $(NoWarn);NU1603
10 |
11 |
12 |
13 |
15 |
16 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Analysis/ProjectAnalysisException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.Serialization;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.CodeGeneration.Analysis
7 | {
8 | #pragma warning disable RCS1194 // Implement exception constructors.
9 | public class ProjectAnalysisException : Exception
10 | #pragma warning restore RCS1194 // Implement exception constructors.
11 | {
12 | public ProjectAnalysisException()
13 | {
14 | }
15 |
16 | public ProjectAnalysisException(string message, ICollection outputLines) : base(message)
17 | {
18 | OutputLines = outputLines;
19 | }
20 |
21 | public ICollection OutputLines { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Generation/Cleaners/ICleaner.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace IntelliTect.Coalesce.CodeGeneration.Generation
5 | {
6 | public interface ICleaner
7 | {
8 | IGenerator Owner { get; set; }
9 |
10 | string TargetPath { get; set; }
11 | bool DryRun { get; set; }
12 |
13 | ///
14 | /// Perform a cleanup with the consideration that the provided list of absolute paths to files should not be removed.
15 | ///
16 | ///
17 | /// A collection of absolute paths to files that should not be modified.
18 | ///
19 | ///
20 | Task CleanupAsync(ICollection knownGoodFiles);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Generation/Generators/GeneratorConfigAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.CodeGeneration.Generation
4 | {
5 | ///
6 | /// Indicates that the targeted property on a generator inheriting from
7 | /// should have its value retrieved from the "generatorConfig" section in the coalesce.json file.
8 | ///
9 | [AttributeUsage(AttributeTargets.Property, Inherited = true)]
10 | public sealed class GeneratorConfigAttribute : Attribute
11 | {
12 |
13 | }
14 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Generation/Services/CompositeGeneratorServices.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Logging;
3 | using IntelliTect.Coalesce.CodeGeneration.Configuration;
4 | using IntelliTect.Coalesce.TypeDefinition;
5 |
6 | namespace IntelliTect.Coalesce.CodeGeneration.Generation
7 | {
8 | public class CompositeGeneratorServices : GeneratorServices
9 | {
10 | public CompositeGeneratorServices(
11 | CoalesceConfiguration config,
12 | ReflectionRepository reflectionRepository,
13 | GenerationContext generationContext,
14 | IServiceProvider serviceProvider,
15 | ILoggerFactory loggerFactory)
16 | : base(config, reflectionRepository, generationContext, loggerFactory)
17 | {
18 | ServiceProvider = serviceProvider;
19 | }
20 |
21 | public IServiceProvider ServiceProvider { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:52047/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "IntelliTect.Coalesce.CodeGeneration": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "http://localhost:52052/"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Templating/Resolution/ITemplateResolver.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.CodeGeneration.Templating.Resolution
2 | {
3 | public interface ITemplateResolver
4 | {
5 | IResolvedTemplate Resolve(TemplateDescriptor descriptor);
6 | }
7 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Templating/Resolution/ResolvedFileSystemTemplate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace IntelliTect.Coalesce.CodeGeneration.Templating.Resolution
8 | {
9 | public class ResolvedFileSystemTemplate : IResolvedTemplate
10 | {
11 | public ResolvedFileSystemTemplate(TemplateDescriptor descriptor, string resolvedPath)
12 | {
13 | TemplateDescriptor = descriptor;
14 | }
15 |
16 | public TemplateDescriptor TemplateDescriptor { get; }
17 |
18 | public bool ResolvedFromDisk => true;
19 |
20 | public string FullName { get; }
21 |
22 | public Stream GetContents()
23 | {
24 | return File.OpenRead(FullName);
25 | }
26 |
27 | public override string ToString() => FullName;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Templating/Resolution/TemplateResolver.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.CodeGeneration.Configuration;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace IntelliTect.Coalesce.CodeGeneration.Templating.Resolution
8 | {
9 | public class TemplateResolver : ITemplateResolver
10 | {
11 | public TemplateResolver(CoalesceConfiguration config)
12 | {
13 | Config = config;
14 | }
15 |
16 | public CoalesceConfiguration Config { get; }
17 |
18 | public IResolvedTemplate Resolve(TemplateDescriptor descriptor)
19 | {
20 | return new ResolvedManifestResourceTemplate(descriptor);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.CodeGeneration/Utilities/ApplicationTimer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.CodeGeneration.Utilities
7 | {
8 | ///
9 | /// Just a static class with a stopwatch for measuring the total elapsed time of code generation.
10 | /// Not started by default - it gets started when the CLI starts.
11 | ///
12 | public static class ApplicationTimer
13 | {
14 | public static readonly Stopwatch Stopwatch = new Stopwatch();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.DotnetTool/IntelliTect.Coalesce.DotnetTool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 | true
11 | coalesce
12 |
13 | dotnet-coalesce
14 | coalesce
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Swashbuckle/CoalesceApiSchemaFilter.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Models;
2 | using Microsoft.OpenApi.Models;
3 | using Swashbuckle.AspNetCore.SwaggerGen;
4 |
5 | namespace IntelliTect.Coalesce.Swashbuckle
6 | {
7 | public class CoalesceApiSchemaFilter : ISchemaFilter
8 | {
9 | public void Apply(OpenApiSchema schema, SchemaFilterContext context)
10 | {
11 | if (context.Type.IsAssignableTo(typeof(ISparseDto)))
12 | {
13 | string description = "This type supports partial/surgical modifications. Properties that are entirely omitted/undefined will be left unchanged on the target object.";
14 |
15 | if (!string.IsNullOrWhiteSpace(schema.Description)) schema.Description += " " + description;
16 | else schema.Description = description;
17 | }
18 |
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Swashbuckle/CoalesceDocumentFilter.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Models;
2 | using Microsoft.OpenApi.Models;
3 | using Swashbuckle.AspNetCore.Swagger;
4 | using Swashbuckle.AspNetCore.SwaggerGen;
5 | using System.IO;
6 | using System.Linq;
7 |
8 | namespace IntelliTect.Coalesce.Swashbuckle
9 | {
10 | public class CoalesceDocumentFilter : IDocumentFilter
11 | {
12 | public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
13 | {
14 | // Get rid of bad schema definitions that we don't use.
15 | var defsToRemove = swaggerDoc.Components.Schemas.Keys.Where(d =>
16 | // These get incorrectly put here if your API surface has file responses.
17 | d.Equals(nameof(IFile)) ||
18 | d.Equals("IFileItemResult") ||
19 | d.Equals(nameof(Stream))
20 | )
21 | .ToList();
22 |
23 | foreach (var definition in defsToRemove)
24 | {
25 | swaggerDoc.Components.Schemas.Remove(definition);
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/Fixtures/TestDbContextFixture.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext;
2 | using IntelliTect.Coalesce.Tests.Util;
3 |
4 | namespace IntelliTect.Coalesce.Tests.Fixtures
5 | {
6 | public class TestDbContextFixture
7 | {
8 | public TestDbContextFixture()
9 | {
10 | Db = new AppDbContext();
11 | CrudContext = new CrudContext(Db, () => new System.Security.Claims.ClaimsPrincipal())
12 | {
13 | ReflectionRepository = ReflectionRepositoryFactory.Reflection
14 | };
15 | }
16 |
17 | public AppDbContext Db { get; }
18 | public CrudContext CrudContext { get; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/.editorconfig:
--------------------------------------------------------------------------------
1 | # Suppress: EC112
2 |
3 | [*.cs]
4 |
5 | # RCS1020: Simplify Nullable to T?.
6 | dotnet_diagnostic.RCS1020.severity = none
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/Bools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace IntelliTect.Coalesce.Tests.TargetClasses
5 | {
6 | internal class Bools
7 | {
8 | public bool NonNullableKeywordName { get; set; }
9 | public Boolean NonNullableClassName { get; set; }
10 | public bool? NullableQuestionMarkKeywordName { get; set; }
11 | public Boolean? NullableQuestionMarkClassName { get; set; }
12 | public Nullable NullableGenericKeywordName { get; set; }
13 | public Nullable NullableGenericClassName { get; set; }
14 |
15 | public bool[] Array { get; set; }
16 | public bool?[] ArrayNullable { get; set; }
17 | public ICollection Collection { get; set; }
18 | public ICollection CollectionNullableItems { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/ComplexInheritance.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.Tests.TargetClasses
7 | {
8 | // IEnumerable is technically duplicated here.
9 | // We specify it explicitly, and IEnumerable<> also implements IEnumerable.
10 | public class ComplexInheritance : IEnumerable, IEnumerable, IAmInheritedMultipleTimes, IAmInheritedMultipleTimes
11 | {
12 | public IEnumerator GetEnumerator()
13 | {
14 | throw new NotImplementedException();
15 | }
16 |
17 | IEnumerator IEnumerable.GetEnumerator()
18 | {
19 | throw new NotImplementedException();
20 | }
21 | }
22 |
23 | public interface IAmInheritedMultipleTimes : IHaveMultipleTypes
24 | {
25 |
26 | }
27 |
28 | public interface IHaveMultipleTypes
29 | {
30 |
31 | }
32 |
33 | public interface IAmSimple
34 | {
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/Github31.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce.Tests.TargetClasses.Github31
6 | {
7 | // https://github.com/IntelliTect/Coalesce/issues/31
8 | internal class Person
9 | {
10 | public int PersonId { get; set; }
11 | public string Name { get; set; }
12 |
13 | public DateTimeOffset? BirthDate { get; set; }
14 |
15 | [Coalesce]
16 | public static ICollection GetMyPeeps()
17 | {
18 | return null;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/CaseProduct.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using System.ComponentModel.DataAnnotations.Schema;
3 |
4 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
5 | {
6 | [Table("CaseProduct")]
7 | public class CaseProduct
8 | {
9 | public int CaseProductId { get; set; }
10 | public int CaseId { get; set; }
11 |
12 | [Search]
13 | [DefaultOrderBy(FieldOrder = 2)]
14 | public Case Case { get; set; }
15 |
16 | public int ProductId { get; set; }
17 |
18 | [Search]
19 | [DefaultOrderBy(FieldOrder = 1)]
20 | public Product Product { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/ComplexModelDependent.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
2 | {
3 | public class ComplexModelDependent
4 | {
5 | public int Id { get; set; }
6 |
7 | // Foreign key without nav prop (discovered by ForeignKeyAttribute on the inverse collection navigation).
8 | public int ParentId { get; set; }
9 |
10 | public string Name { get; set; }
11 |
12 | [Coalesce]
13 | public CaseDtoStandalone SameMethodNameAsMethodOnDifferentType(CaseDtoStandalone input) => input;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/EnumPk.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.ComponentModel.DataAnnotations;
5 | using System.Text;
6 |
7 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
8 | {
9 | public enum EnumPkId
10 | {
11 | Value0 = 0,
12 | Value1 = 1,
13 | Value10 = 10,
14 | }
15 |
16 | public class EnumPk
17 | {
18 | [Key]
19 | [DatabaseGenerated(DatabaseGeneratedOption.None)]
20 | public EnumPkId EnumPkId { get; set; }
21 |
22 | public string Name { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/InternalUseClass.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
7 | {
8 | internal class InternalClass
9 | {
10 | }
11 |
12 | [InternalUse]
13 | public class InternalUseClass
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/MultipleParents.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
4 | {
5 | public class MultipleParents
6 | {
7 | public int Id { get; set; }
8 |
9 | public int? Parent1Id { get; set; }
10 | public Parent1 Parent1 { get; set; }
11 |
12 | public int? Parent2Id { get; set; }
13 | public Parent2 Parent2 { get; set; }
14 | }
15 |
16 | public class Parent1
17 | {
18 | public int Id { get; set; }
19 | public List Children { get; set; }
20 | }
21 |
22 | public class Parent2
23 | {
24 | public int Id { get; set; }
25 | public List Children { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/Records.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext;
7 |
8 | public record PositionalRecord(string String, int Num)
9 | {
10 | public DateTime Date { get; init; }
11 | }
12 |
13 | public record InitRecordWithDefaultCtor
14 | {
15 | public string String { get; init; }
16 |
17 | [Read("ReadRole"), Edit("EditRole")]
18 | public int Num { get; init; }
19 |
20 | [DtoIncludes("asdf"), DtoExcludes("qwert")]
21 | public PositionalRecord NestedRecord { get; init; }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/RecursiveHierarchy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | #nullable enable
9 |
10 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
11 | {
12 | public class RecursiveHierarchy
13 | {
14 | public int Id { get; set; }
15 |
16 | public string? Name { get; set; }
17 |
18 | public int? ParentId { get; set; }
19 | public RecursiveHierarchy? Parent { get; set; }
20 |
21 | [InverseProperty(nameof(Parent))]
22 | public List Children { get; set; } = new();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/RequiredAndInitModel.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
3 | {
4 | public class RequiredAndInitModel
5 | {
6 | public int Id { get; set; }
7 |
8 | public required string RequiredRef { get; set; }
9 | public required int RequiredValue { get; set; }
10 | public required string RequiredInitRef { get; init; }
11 | public required int RequiredInitValue { get; init; }
12 | public string InitRef { get; init; }
13 | public int InitValue { get; init; }
14 | public int? NullableInitValue { get; init; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/RoleNames.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
6 | {
7 | public static class RoleNames
8 | {
9 | public const string User = "User";
10 | public const string Admin = "Admin";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/Sibling.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
2 | {
3 | public class Sibling
4 | {
5 | public int SiblingId { get; set; }
6 |
7 | public int PersonId { get; set; }
8 | public Person Person { get; set; }
9 |
10 | public int PersonTwoId { get; set; }
11 | public Person PersonTwo { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/Test.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace IntelliTect.Coalesce.Tests.TargetClasses
8 | {
9 | // This class is deliberately named "Test", since the name "Test" also occurs in its namespace.
10 | // This class is intended for testing resolutions to issues like https://github.com/IntelliTect/Coalesce/issues/28
11 | public class Test
12 | {
13 | public int TestId { get; set; }
14 |
15 | public int ComplexModelId { get; set; }
16 | public ComplexModel ComplexModel { get; set; }
17 |
18 | [ListText]
19 | public string TestName { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/ZipCode.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations.Schema;
2 | using System.ComponentModel.DataAnnotations;
3 | using IntelliTect.Coalesce.DataAnnotations;
4 |
5 | namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
6 | {
7 | public class ZipCode
8 | {
9 | [Key]
10 | [DatabaseGenerated(DatabaseGeneratedOption.None)]
11 | [ListText]
12 | public string Zip { get; set; } = null!;
13 |
14 | public string State { get; set; } = null!;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/Tests/ApplicationTests.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 |
10 | namespace IntelliTect.Coalesce.Tests.Tests
11 | {
12 | public class ApplicationTests
13 | {
14 | [Fact]
15 | public void AddCoalesce_DoesNotExplicitlyRequireWebServices()
16 | {
17 | // Ensures that esoteric testing scenarios can setup Coalesce services
18 | // without a full aspnetcore host builder.
19 |
20 | var services = new ServiceCollection();
21 |
22 | services.AddDbContext();
23 | services.AddCoalesce(b => b.AddContext());
24 |
25 | var sp = services.BuildServiceProvider();
26 |
27 | Assert.NotNull(sp.GetRequiredService>());
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/Tests/ClonerTest.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Helpers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 |
8 | namespace IntelliTect.Coalesce.Tests
9 | {
10 | public class ClonerTest
11 | {
12 | [Fact]
13 | public void CopyTest()
14 | {
15 | var src = new TestClass
16 | {
17 | I = 34,
18 | S = "My String",
19 | C = new TestClass()
20 | };
21 | src.C.I = 12;
22 | src.Field = "my Field";
23 | var dest = src.Copy();
24 |
25 | Assert.Equal(src.I, dest.I);
26 | Assert.Equal(src.S, dest.S);
27 | Assert.Equal(src.Field, dest.Field);
28 | Assert.Same(src.C, dest.C);
29 | }
30 |
31 |
32 |
33 | public class TestClass
34 | {
35 | public string S { get; set; }
36 | public int I { get; set; }
37 | public TestClass C { get; set; }
38 | public double Test() { return 1.0; }
39 |
40 | public string Field;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Tests/xunit.runner.json:
--------------------------------------------------------------------------------
1 | {
2 | "methodDisplay": "method"
3 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce.Vue/IntelliTect.Coalesce.Vue.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Vue.js shared code for server projects for IntelliTect.Coalesce
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Behaviors/BehaviorsModelBinderProvider.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using Microsoft.AspNetCore.Mvc.ModelBinding;
3 | using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
4 | using System;
5 |
6 | namespace IntelliTect.Coalesce.Api.Behaviors
7 | {
8 | public class BehaviorsModelBinderProvider : IModelBinderProvider
9 | {
10 | public IModelBinder? GetBinder(ModelBinderProviderContext context)
11 | {
12 | if (context == null)
13 | {
14 | throw new ArgumentNullException(nameof(context));
15 | }
16 |
17 | var typeViewModel = new ReflectionTypeViewModel(context.Metadata.ModelType);
18 | if (!typeViewModel.IsA(typeof(IBehaviors<>))) return null;
19 |
20 | return new BinderTypeModelBinder(typeof(BehaviorsModelBinder));
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Behaviors/IBehaviorsFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using IntelliTect.Coalesce.TypeDefinition;
3 | using Microsoft.AspNetCore.Hosting.Server;
4 |
5 | namespace IntelliTect.Coalesce.Api.Behaviors
6 | {
7 | public interface IBehaviorsFactory
8 | {
9 | object GetBehaviors(ClassViewModel servedType, ClassViewModel declaredFor);
10 |
11 | Type GetBehaviorsType(ClassViewModel servedType, ClassViewModel declaredFor);
12 |
13 | IBehaviors GetBehaviors(ClassViewModel declaredFor)
14 | where TServed : class;
15 |
16 | object GetDefaultBehaviors(ClassViewModel servedType);
17 |
18 | }
19 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Behaviors/IEntityFrameworkBehaviors.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce
7 | {
8 | ///
9 | /// Marker interface for the behaviors that will be used when handling entity types for which no custom behaviors are resolved.
10 | ///
11 | /// The entity type handled.
12 | /// The context that serves the entity.
13 | public interface IEntityFrameworkBehaviors : IBehaviors
14 | where T : class
15 | where TContext : DbContext
16 | {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Behaviors/SaveKind.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce
2 | {
3 | public enum SaveKind
4 | {
5 | Create,
6 | Update,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Controllers/IApiActionFilter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Filters;
2 |
3 | namespace IntelliTect.Coalesce.Api.Controllers
4 | {
5 | ///
6 | /// Marker interface for the filter that will handle error reponses and model validation for API Controllers.
7 | ///
8 | public interface IApiActionFilter : IActionFilter, IAlwaysRunResultFilter { }
9 | }
10 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/CrudStrategy/IStandardCrudStrategy.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using Microsoft.EntityFrameworkCore;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Security.Claims;
6 | using System.Text;
7 |
8 | namespace IntelliTect.Coalesce.Api
9 | {
10 | public interface IStandardCrudStrategy
11 | {
12 | ///
13 | /// The user making the request.
14 | ///
15 | ClaimsPrincipal? User { get; }
16 |
17 | ///
18 | /// A ClassViewModel representing the type T that is handled by these strategies.
19 | ///
20 | ClassViewModel ClassViewModel { get; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/DataSourceModelBinderProvider.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using Microsoft.AspNetCore.Mvc.ModelBinding;
3 | using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
4 | using System;
5 |
6 | namespace IntelliTect.Coalesce.Api.DataSources
7 | {
8 | public class DataSourceModelBinderProvider : IModelBinderProvider
9 | {
10 | public IModelBinder? GetBinder(ModelBinderProviderContext context)
11 | {
12 | if (context == null)
13 | {
14 | throw new ArgumentNullException(nameof(context));
15 | }
16 |
17 | var typeViewModel = new ReflectionTypeViewModel(context.Metadata.ModelType);
18 | if (!typeViewModel.IsA(typeof(IDataSource<>))) return null;
19 |
20 | return new BinderTypeModelBinder(typeof(DataSourceModelBinder));
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/DataSourceNotFoundException.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.Api.DataSources
7 | {
8 | #pragma warning disable RCS1194 // Implement exception constructors.
9 | public class DataSourceNotFoundException : Exception
10 | #pragma warning restore RCS1194 // Implement exception constructors.
11 | {
12 | private readonly ClassViewModel servedType;
13 | private readonly ClassViewModel declaredFor;
14 | private readonly string dataSourceName;
15 |
16 | public DataSourceNotFoundException(ClassViewModel servedType, ClassViewModel declaredFor, string dataSourceName)
17 | {
18 | this.servedType = servedType;
19 | this.declaredFor = declaredFor;
20 | this.dataSourceName = dataSourceName;
21 | }
22 |
23 | public override string Message => $"A DataSource named {dataSourceName} declared for {declaredFor} that serves type {servedType} could not be found";
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/DefaultDataSourceAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce
6 | {
7 | ///
8 | /// Indicate that an IDataSource<T> is the default implementation for its type T.
9 | /// This DataSource will displace the standard implementation for its served type.
10 | /// Any references to "Default", and any requests with no specified DataSource, will use this type.
11 | ///
12 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
13 | public sealed class DefaultDataSourceAttribute : Attribute
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/IDataSource.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Models;
2 | using System.Threading.Tasks;
3 |
4 | namespace IntelliTect.Coalesce
5 | {
6 |
7 | public interface IDataSource
8 | where T : class
9 | {
10 | Task> GetItemAsync(object id, IDataSourceParameters parameters);
11 |
12 | Task> GetMappedItemAsync(object id, IDataSourceParameters parameters)
13 | where TDto : class, IResponseDto, new();
14 |
15 | Task> GetListAsync(IListParameters parameters);
16 |
17 | Task> GetMappedListAsync(IListParameters parameters)
18 | where TDto : class, IResponseDto, new();
19 |
20 | Task> GetCountAsync(IFilterParameters parameters);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/IDataSourceFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using IntelliTect.Coalesce.TypeDefinition;
3 |
4 | namespace IntelliTect.Coalesce.Api.DataSources
5 | {
6 | public interface IDataSourceFactory
7 | {
8 | object GetDataSource(ClassViewModel servedType, ClassViewModel declaredFor, string? dataSourceName = null);
9 |
10 | Type GetDataSourceType(ClassViewModel servedType, ClassViewModel declaredFor, string? dataSourceName = null);
11 |
12 | IDataSource GetDataSource(ClassViewModel declaredFor, string? dataSourceName)
13 | where TServed : class;
14 |
15 | IDataSource GetDataSource(string? dataSourceName)
16 | where TServed : class
17 | where TDeclaredFor : class;
18 |
19 | object GetDefaultDataSource(ClassViewModel servedType, ClassViewModel declaredFor);
20 |
21 | IDataSource GetDefaultDataSource(ClassViewModel declaredFor)
22 | where TServed : class;
23 |
24 | IDataSource GetDefaultDataSource()
25 | where TServed : class
26 | where TDeclaredFor : class;
27 | }
28 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/IEntityFrameworkDataSource.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce
7 | {
8 | ///
9 | /// Marker interface for the data source that will be used when serving entity types for which no custom data source is resolved.
10 | ///
11 | /// The entity type served
12 | /// The context that serves the entity.
13 | public interface IEntityFrameworkDataSource : IDataSource
14 | where T : class
15 | where TContext : DbContext
16 | {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DataSources/IResultTransformer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace IntelliTect.Coalesce
5 | {
6 | public interface IResultTransformer
7 | where T : class
8 | {
9 | Task TransformResultsAsync(IReadOnlyList results, IDataSourceParameters parameters);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/DeclaredForAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce
4 | {
5 | ///
6 | /// Used to hint that a IDataSource or IBehaviors instance is declared for the given type.
7 | /// This is used both when defining such a class for an IClassDto as well as when such an instance needs to be model-bound.
8 | ///
9 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class)]
10 | public class DeclaredForAttribute : Attribute
11 | {
12 | public DeclaredForAttribute(Type declaredFor)
13 | {
14 | DeclaredFor = declaredFor ?? throw new ArgumentNullException(nameof(declaredFor));
15 | }
16 |
17 | public Type DeclaredFor { get; }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Parameters/DataSourceParameters.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.Api
2 | {
3 | public class DataSourceParameters : IDataSourceParameters
4 | {
5 | ///
6 | public string? Includes { get; set; }
7 |
8 | ///
9 | public string? DataSource { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Parameters/FilterParameters.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace IntelliTect.Coalesce.Api
5 | {
6 | public class FilterParameters : DataSourceParameters, IFilterParameters
7 | {
8 | ///
9 | public string? Search { get; set; }
10 |
11 | ///
12 | public Dictionary Filter { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
13 |
14 | ///
15 | IDictionary IFilterParameters.Filter => Filter;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Parameters/IDataSourceParameters.cs:
--------------------------------------------------------------------------------
1 | // Explicitly in IntelliTect.Coalesce to simplify typical using statements
2 | namespace IntelliTect.Coalesce
3 | {
4 | public interface IDataSourceParameters
5 | {
6 | ///
7 | /// The "include" string specified by the client.
8 | /// Used primarily for property-level DTO trimming.
9 | /// Specifying "none" will prevent the default query behavior of
10 | /// including all immediate relations when using the StandardDataSource.
11 | ///
12 | string? Includes { get; }
13 |
14 | ///
15 | /// The name of the data source that was requested by the client.
16 | /// This could be different than the name of the data source that gets resolved
17 | /// (in the event of overridden default data sources).
18 | ///
19 | string? DataSource { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Parameters/IFilterParameters.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | // Explicitly in IntelliTect.Coalesce to simplify typical using statements
6 | namespace IntelliTect.Coalesce
7 | {
8 | public interface IFilterParameters : IDataSourceParameters
9 | {
10 | ///
11 | /// A free-form search string.
12 | ///
13 | string? Search { get; }
14 |
15 | ///
16 | /// A mapping of values, keyed by field name, on which to filter.
17 | /// It is the responsibility of the consumer to decide how to interpret these values.
18 | ///
19 | IDictionary Filter { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Api/Parameters/SortDirection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce
6 | {
7 | public enum SortDirection
8 | {
9 | ///
10 | /// Ascending
11 | ///
12 | Asc = 1,
13 |
14 | ///
15 | /// Descending
16 | ///
17 | Desc = 2,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Application/DefaultTimeZoneResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce
6 | {
7 | internal class StaticTimeZoneResolver : ITimeZoneResolver
8 | {
9 | public StaticTimeZoneResolver(TimeZoneInfo timeZoneInfo) {
10 | TimeZoneInfo = timeZoneInfo;
11 | }
12 |
13 | public TimeZoneInfo TimeZoneInfo { get; }
14 |
15 | public TimeZoneInfo GetTimeZoneInfo() => TimeZoneInfo;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Application/ITimeZoneResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce
6 | {
7 | public interface ITimeZoneResolver
8 | {
9 | TimeZoneInfo GetTimeZoneInfo();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/ClientValidationAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | [System.AttributeUsage(System.AttributeTargets.Property)]
9 | public class ClientValidationAttribute: System.Attribute
10 | {
11 | public bool IsRequired { get; set; }
12 |
13 | // Note: nullable propeties can't be used here because nullable values can't be used as attribute initializers.
14 | public double MinValue { get; set; } = double.MaxValue;
15 | public double MaxValue { get; set; } = double.MinValue;
16 | public int MinLength { get; set; } = int.MaxValue;
17 | public int MaxLength { get; set; } = int.MinValue;
18 |
19 | public string? Pattern { get; set; }
20 | public bool IsEmail { get; set; }
21 | public bool IsPhoneUs { get; set; }
22 |
23 | ///
24 | /// Gets or sets an error message to associate with a validation control if validation fails.
25 | ///
26 | public string? ErrorMessage { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/CoalesceAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce
6 | {
7 | ///
8 | /// The targeted class or method should be exposed by Coalesce.
9 | /// Different types will be exposed in different ways. See documentation for details.
10 | ///
11 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Interface | AttributeTargets.Enum)]
12 | public sealed class CoalesceAttribute : Attribute
13 | {
14 | ///
15 | /// When placed on a type, overrides the name of the type used in client-side code.
16 | ///
17 | public string? ClientTypeName { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/CreateAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using IntelliTect.Coalesce.Helpers;
3 |
4 | namespace IntelliTect.Coalesce.DataAnnotations
5 | {
6 | ///
7 | ///
8 | /// When placed on an entity or custom class exposed by Coalesce,
9 | /// controls the permissions for saving new instances of the model via the /save or /bulkSave endpoints.
10 | ///
11 | ///
12 | [AttributeUsage(AttributeTargets.Class)]
13 | public sealed class CreateAttribute : SecurityAttribute
14 | {
15 | public CreateAttribute()
16 | {
17 | }
18 |
19 | public CreateAttribute(SecurityPermissionLevels permissionLevel)
20 | {
21 | PermissionLevel = permissionLevel;
22 | }
23 |
24 | public CreateAttribute(params string[] roles)
25 | {
26 | Roles = string.Join(",", roles);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/CreateControllerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// Allows specifying the types of controllers to create. Not including will create all.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Class)]
12 | [Obsolete("Use security attributes (Read/Edit/Create/Delete) or InternalUse to hide parts of entities or whole entities from Coalesce APIs")]
13 | public class CreateControllerAttribute : System.Attribute
14 | {
15 | public bool WillCreateView { get; set; }
16 | public bool WillCreateApi { get; set; }
17 |
18 | public CreateControllerAttribute(bool willCreateView = true, bool willCreateApi = true)
19 | {
20 | WillCreateView = willCreateView;
21 | WillCreateApi = willCreateApi;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/DateTypeAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// Allows specifying the type of date to contain.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Property)]
12 | public class DateTypeAttribute : System.Attribute
13 | {
14 | public enum DateTypes
15 | {
16 | DateTime = 0,
17 | DateOnly = 1,
18 | TimeOnly = 2,
19 | }
20 |
21 | public DateTypes DateType { get; set; }
22 |
23 | public DateTypeAttribute(DateTypes dateType = DateTypes.DateTime)
24 | {
25 | this.DateType = dateType;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/DeleteAttribute.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Helpers;
2 | using System;
3 |
4 | namespace IntelliTect.Coalesce.DataAnnotations
5 | {
6 | ///
7 | ///
8 | /// When placed on an entity or custom class exposed by Coalesce,
9 | /// controls the permissions for the deleting existing instances of the model via the /delete or /bulkSave endpoints.
10 | ///
11 | ///
12 | [AttributeUsage(AttributeTargets.Class)]
13 | public class DeleteAttribute : SecurityAttribute
14 | {
15 | public DeleteAttribute()
16 | {
17 | }
18 |
19 | public DeleteAttribute(SecurityPermissionLevels permissionLevel)
20 | {
21 | PermissionLevel = permissionLevel;
22 | }
23 |
24 | public DeleteAttribute(params string[] roles)
25 | {
26 | Roles = string.Join(",", roles);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/DtoExcludesAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.DataAnnotations
4 | {
5 | ///
6 | /// Specify that this property is only used on specific views of the content.
7 | ///
8 | [AttributeUsage(AttributeTargets.Property)]
9 | public class DtoExcludesAttribute : Attribute
10 | {
11 | ///
12 | /// Comma-delimited list of content views this property should be excluded from.
13 | ///
14 | public string ContentViews { get; set; } = "";
15 |
16 | public DtoExcludesAttribute( )
17 | {
18 |
19 | }
20 |
21 | public DtoExcludesAttribute(string contentViews)
22 | {
23 | ContentViews = contentViews;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/DtoIncludesAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.DataAnnotations
4 | {
5 | ///
6 | /// Specify that this property is only used on specific views of the content.
7 | ///
8 | [AttributeUsage(AttributeTargets.Property)]
9 | public class DtoIncludesAttribute : Attribute
10 | {
11 | ///
12 | /// Comma-delimited list of content views this property should be included on.
13 | ///
14 | public string ContentViews { get; set; } = "";
15 |
16 | public DtoIncludesAttribute()
17 | {
18 |
19 | }
20 |
21 | public DtoIncludesAttribute( string contentViews )
22 | {
23 | ContentViews = contentViews;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/HiddenAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// Allows this property to be hidden on the list or editor or both.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Method)]
12 | public class HiddenAttribute : System.Attribute
13 | {
14 | [Flags]
15 | public enum Areas
16 | {
17 | None = 0,
18 | List = 1 << 0,
19 | Edit = 1 << 1,
20 | All = List | Edit,
21 | }
22 |
23 | public Areas Area { get; set; }
24 |
25 | public HiddenAttribute(Areas area = Areas.All)
26 | {
27 | this.Area = area;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/InjectAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// When placed on a method parameter declaration, causes the parameter to be injected from the application's IServiceContainer.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Parameter)]
12 | public class InjectAttribute : Attribute
13 | {
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/InternalUseAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using static System.AttributeTargets;
6 |
7 | namespace IntelliTect.Coalesce.DataAnnotations
8 | {
9 | ///
10 | /// Types and members marked [InternalUse] are not exposed by Coalesce's generated APIs.
11 | ///
12 | [System.AttributeUsage(Property | Method | Class | Struct)]
13 | public class InternalUseAttribute : Attribute
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/ListTextAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// The property marked with the attribute will be shown in drop down lists.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Property)]
12 | public class ListTextAttribute : System.Attribute
13 | {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/LoadFromDataSourceAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce.DataAnnotations
6 | {
7 | ///
8 | /// Specify that the targeted model instance method should load the instance it is called on
9 | /// from the specified data source when invoked from an API endpoint.
10 | /// By default, whatever the default data source for the model's type will be used.
11 | ///
12 | [AttributeUsage(AttributeTargets.Method)]
13 | [Obsolete("LoadFromDataSourceAttribute has been merged into ExecuteAttribute")]
14 | public sealed class LoadFromDataSourceAttribute : Attribute
15 | {
16 | public LoadFromDataSourceAttribute(Type dataSourceType)
17 | {
18 | DataSourceType = dataSourceType;
19 | }
20 |
21 | public Type DataSourceType { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/ManyToManyAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// Identifies a property as a many to many relationship and creates a secondary property on the view model for
10 | /// viewing the collection of target items directly.
11 | ///
12 | [System.AttributeUsage(AttributeTargets.Property)]
13 | public class ManyToManyAttribute : System.Attribute
14 | {
15 | public string CollectionName { get; }
16 |
17 | ///
18 | /// The name of the navigation property on the middle entity that points at the far side of the many-to-many relationship.
19 | ///
20 | public string? FarNavigationProperty { get; set; }
21 |
22 | public ManyToManyAttribute(string collectionName)
23 | {
24 | CollectionName = collectionName;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/ReadOnlyApiAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.DataAnnotations
7 | {
8 | ///
9 | /// Properties marked ReadOnlyApi are not saved.
10 | ///
11 | [System.AttributeUsage(System.AttributeTargets.Property)]
12 | [Obsolete("Mark a property with the [Read] attribute with no [Edit] attribute to make it read-only")]
13 | public class ReadOnlyApiAttribute : System.Attribute
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/RestrictAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.DataAnnotations
4 | {
5 | [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
6 | public sealed class RestrictAttribute : Attribute
7 | where T : IPropertyRestriction
8 | {
9 | // Originally, there was a design of this attribute that had the attribute itself implementing
10 | // `IPropertyRestriction`, but this design of the attribute itself implementing the functionality
11 | // presents with a major problem:
12 |
13 | // We'd like to have a `IPropertyRestriction` instance per mapping operation
14 | // so that instances can be constructed with dependency injection and also cache
15 | // state for reuse within the same mapping operation. This doesn't work with
16 | // attribute instances which are instantiated by the runtime.
17 |
18 | // So, this attribute only functions as a marker attribute for discovery of T.
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/ServiceAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce
7 | {
8 | ///
9 | ///
10 | /// The targeted class or interface will be exposed as a service by Coalesce.
11 | ///
12 | ///
13 | /// All methods of a targeted interface, or all public methods marked with of a targeted class,
14 | /// will have an API endpoint generated.
15 | ///
16 | ///
17 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
18 | public sealed class ServiceAttribute : Attribute
19 | {
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/DataAnnotations/StandaloneEntityAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce
7 | {
8 |
9 | ///
10 | ///
11 | /// The targeted class or interface will be exposed as a standalone entity by Coalesce.
12 | ///
13 | ///
14 | /// The class will behave as if it is a standard -mapped entity type,
15 | /// except it must provide its own definition of a
16 | /// and (behaviors are optional for read-only types).
17 | ///
18 | ///
19 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
20 | public sealed class StandaloneEntityAttribute : Attribute
21 | {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Helpers/Cloner.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using System;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Threading.Tasks;
8 |
9 | namespace IntelliTect.Coalesce.Helpers
10 | {
11 | public static class Cloner
12 | {
13 | ///
14 | /// Makes a shallow copy of an object.
15 | ///
16 | ///
17 | ///
18 | public static T Copy(this T source) where T : class
19 | {
20 | return (T)_MemberwiseCloneMethodInfo.Invoke(source, null)!;
21 | }
22 |
23 | private static MethodInfo _MemberwiseCloneMethodInfo = typeof(object)
24 | .GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance)!;
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Helpers/EnumExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Threading.Tasks;
7 |
8 | namespace IntelliTect.Coalesce.Helpers
9 | {
10 | public static class EnumExtensions
11 | {
12 | public static string? GetDisplayName(this Enum value)
13 | {
14 | return value.GetType()
15 | .GetMember(value.ToString())
16 | .First()
17 | .GetCustomAttribute()
18 | ?.GetName()
19 | ?? value.ToString();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Helpers/Search/SearchableProperty.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Security.Claims;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace IntelliTect.Coalesce.Helpers.Search
11 | {
12 | public abstract class SearchableProperty
13 | {
14 | public SearchableProperty(PropertyViewModel prop)
15 | {
16 | Property = prop;
17 | }
18 |
19 | public PropertyViewModel Property { get; protected set; }
20 |
21 | protected virtual string PropertyNamePath => Property.Name;
22 |
23 | public abstract IEnumerable<(PropertyViewModel property, Expression statement)> GetLinqSearchStatements(
24 | CrudContext context, Expression propertyParent, string rawSearchTerm);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/IntelliTect.Coalesce.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Core framework library for IntelliTect.Coalesce
5 | AnyCPU
6 |
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Mapping/IMappingContext.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Security.Claims;
5 |
6 | namespace IntelliTect.Coalesce
7 | {
8 | public interface IMappingContext
9 | {
10 | string? Includes { get; }
11 | ClaimsPrincipal User { get; }
12 |
13 | bool IsInRoleCached(string role);
14 |
15 | void AddMapping(object sourceObject, IncludeTree? includeTree, object mappedObject);
16 |
17 | bool TryGetMapping(
18 | object sourceObject,
19 | IncludeTree? includeTree,
20 | [System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
21 | out TDto? mappedObject
22 | )
23 | where TDto : class;
24 |
25 | IPropertyRestriction GetPropertyRestriction(Type type);
26 | TRestriction GetPropertyRestriction()
27 | where TRestriction : IPropertyRestriction
28 | => (TRestriction)GetPropertyRestriction(typeof(TRestriction));
29 | }
30 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Mapping/IncludeTree/IIncludedSeparatelyQueryable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace IntelliTect.Coalesce.Mapping.IncludeTrees
8 | {
9 | public interface IIncludedSeparatelyQueryable : IQueryable
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Mapping/IncludeTree/IncludedSeparatelyQueryable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Threading.Tasks;
7 |
8 | namespace IntelliTect.Coalesce.Mapping.IncludeTrees
9 | {
10 | public class IncludedSeparatelyQueryable : IIncludedSeparatelyQueryable
11 | {
12 | private readonly IQueryable _queryable;
13 |
14 | public IncludedSeparatelyQueryable(IQueryable queryable)
15 | {
16 | _queryable = queryable;
17 | }
18 |
19 | public Expression Expression => _queryable.Expression;
20 | public Type ElementType => _queryable.ElementType;
21 | public IQueryProvider Provider => _queryable.Provider;
22 |
23 | public IEnumerator GetEnumerator() => _queryable.GetEnumerator();
24 |
25 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Models/ApiResult.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.Models
2 | {
3 | public class ApiResult
4 | {
5 | public bool WasSuccessful { get; set; } = true;
6 |
7 | public string? Message { get; set; }
8 |
9 | ///
10 | /// Controls the shape of the DTO mapping of the result object.
11 | ///
12 | [System.Text.Json.Serialization.JsonIgnore]
13 | [System.Runtime.Serialization.IgnoreDataMember] // for newtonsoft
14 | public IncludeTree? IncludeTree { get; set; }
15 |
16 | public ApiResult() { }
17 |
18 | public ApiResult(bool wasSuccessful, string? message = null)
19 | {
20 | WasSuccessful = wasSuccessful;
21 | Message = message;
22 | }
23 |
24 | public ApiResult(string? errorMessage) : this(false, errorMessage) { }
25 |
26 | public ApiResult(ApiResult result) : this(result.WasSuccessful, result.Message)
27 | {
28 | IncludeTree = result.IncludeTree;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Models/FileParameter.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.Api.Controllers;
2 | using System.IO;
3 |
4 | namespace IntelliTect.Coalesce.Models
5 | {
6 | public class FileParameter : IFile
7 | {
8 | public required byte[] Content { get; set; }
9 |
10 | public string? ContentType { get; set; }
11 |
12 | public string? Name { get; set; }
13 |
14 | public long Length => Content.Length;
15 |
16 | bool IFile.ForceDownload => false;
17 | Stream? IFile.Content => new MemoryStream(Content);
18 |
19 | public static implicit operator File(FileParameter param) => new File
20 | {
21 | Content = ((IFile)param).Content,
22 | ContentType = param.ContentType,
23 | Length = param.Length,
24 | Name = param.Name,
25 | };
26 |
27 | public static implicit operator FileParameter(File param) => new FileParameter
28 | {
29 | Content = param.Content?.ReadAllBytes() ?? [],
30 | ContentType = param.ContentType,
31 | Name = param.Name,
32 | };
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Models/IFile.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace IntelliTect.Coalesce.Models
4 | {
5 | ///
6 | /// Representation of a file for use in Coalesce method parameters and returns.
7 | ///
8 | public interface IFile
9 | {
10 | Stream? Content { get; }
11 | string? ContentType { get; }
12 | string? Name { get; }
13 | long Length { get; }
14 | bool ForceDownload { get; }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Models/ValidationIssue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.Models
4 | {
5 | public class ValidationIssue
6 | {
7 | public string Property { get; set; }
8 | public string Issue { get; set; }
9 |
10 | public ValidationIssue(string property, string issue)
11 | {
12 | Property = property ?? throw new ArgumentNullException(nameof(property));
13 | Issue = issue ?? throw new ArgumentNullException(nameof(issue));
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: InternalsVisibleTo("IntelliTect.Coalesce.CodeGeneration")]
6 | [assembly: InternalsVisibleTo("IntelliTect.Coalesce.AuditLogging")]
7 | [assembly: InternalsVisibleTo("IntelliTect.Coalesce.Tests")]
8 | [assembly: InternalsVisibleTo("IntelliTect.Coalesce.CodeGeneration.Tests")]
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeDefinition/EnumMember.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce.TypeDefinition
6 | {
7 | public class EnumMember
8 | {
9 | public EnumMember(
10 | string name,
11 | object value,
12 | string displayName,
13 | string? description,
14 | string? comment = null
15 | )
16 | {
17 | Name = name;
18 | DisplayName = displayName;
19 | Value = value;
20 | Description = description;
21 | Comment = comment;
22 | }
23 |
24 | public string Name { get; }
25 | public object Value { get; }
26 | public string DisplayName { get; }
27 | public string? Description { get; }
28 | public string? Comment { get; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeDefinition/Enums/PropertyRole.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace IntelliTect.Coalesce.TypeDefinition.Enums
6 | {
7 | [Flags]
8 | public enum PropertyRole
9 | {
10 | Value,
11 | ReferenceNavigation,
12 | CollectionNavigation,
13 | PrimaryKey,
14 | ForeignKey,
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeDefinition/MethodReturnViewModel.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | #nullable enable
6 |
7 | namespace IntelliTect.Coalesce.TypeDefinition
8 | {
9 | ///
10 | /// Shim of a method's return value so it can be treated as an IValueViewModel.
11 | ///
12 | public class MethodReturnViewModel : ValueViewModel
13 | {
14 | internal MethodReturnViewModel(MethodViewModel method) : base(method.ResultType)
15 | {
16 | Method = method;
17 | }
18 |
19 | public override string Name => "$return";
20 |
21 | public override string DisplayName => "Result"; // TODO: i18n
22 |
23 | public override string? Description => null;
24 |
25 | public MethodViewModel Method { get; }
26 |
27 | public override bool IsRequired => false;
28 |
29 | public override IEnumerable> GetAttributes()
30 | => Method.GetAttributes();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeDefinition/Security/MethodSecurityInfo.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.DataAnnotations;
2 | using IntelliTect.Coalesce.Helpers;
3 | using IntelliTect.Coalesce.TypeDefinition;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Security.Claims;
8 |
9 | namespace IntelliTect.Coalesce.TypeDefinition
10 | {
11 | public class MethodSecurityInfo
12 | {
13 | public MethodSecurityInfo(SecurityPermission execute)
14 | {
15 | Execute = execute;
16 | }
17 |
18 | public SecurityPermission Execute { get; }
19 |
20 | public bool IsExecuteAllowed(ClaimsPrincipal? user) => Execute.IsAllowed(user);
21 |
22 | public override string ToString() => $"Execute: {Execute}";
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeDefinition/TypeDiscriminator.cs:
--------------------------------------------------------------------------------
1 | namespace IntelliTect.Coalesce.TypeDefinition
2 | {
3 | public enum TypeDiscriminator
4 | {
5 | Unknown,
6 | Void,
7 | Number,
8 | String,
9 | Boolean,
10 | Date,
11 | Enum,
12 | Model,
13 | Object,
14 | Collection,
15 | File,
16 | Binary
17 | }
18 |
19 | public static class TypeDiscriminatorExtensions
20 | {
21 | public static bool IsCustomType(this TypeDiscriminator type)
22 | {
23 | return type == TypeDiscriminator.Enum || type.IsClassType();
24 | }
25 |
26 | public static bool IsClassType(this TypeDiscriminator type)
27 | {
28 | return type == TypeDiscriminator.Model || type == TypeDiscriminator.Object;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/TypeUsage/EntityTypeUsage.cs:
--------------------------------------------------------------------------------
1 | using IntelliTect.Coalesce.TypeDefinition;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace IntelliTect.Coalesce.TypeUsage
7 | {
8 | public class EntityTypeUsage
9 | {
10 | public EntityTypeUsage(DbContextTypeUsage context, TypeViewModel typeViewModel, string contextPropertyName)
11 | {
12 | Context = context;
13 | TypeViewModel = typeViewModel;
14 | ClassViewModel = typeViewModel.ClassViewModel ?? throw new ArgumentException("Entity is not a class", nameof(typeViewModel));
15 | ContextPropertyName = contextPropertyName;
16 | }
17 |
18 | public DbContextTypeUsage Context { get; }
19 |
20 | public TypeViewModel TypeViewModel { get; }
21 |
22 | public ClassViewModel ClassViewModel { get; }
23 |
24 | public string ContextPropertyName { get; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Utilities/EntityFrameworkServiceProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Infrastructure;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using System;
5 | using System.Linq;
6 |
7 | namespace IntelliTect.Coalesce.Utilities;
8 |
9 | internal class EntityFrameworkServiceProvider(DbContext db) : IServiceProvider
10 | {
11 | public object? GetService(Type serviceType)
12 | {
13 | // From Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions;
14 | // Copied directly to avoid having to dynamically create generic overloads at runtime,
15 | // and also because we don't want to throw for services not found - we want to return null.
16 |
17 | var internalServiceProvider = db.GetInfrastructure();
18 |
19 | return internalServiceProvider.GetService(serviceType)
20 | ?? internalServiceProvider.GetService()
21 | ?.Extensions.OfType().FirstOrDefault()
22 | ?.ApplicationServiceProvider
23 | ?.GetService(serviceType);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Utilities/LazyValue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IntelliTect.Coalesce.Utilities
4 | {
5 | internal struct LazyValue
6 | {
7 | bool HasValue;
8 | T Value;
9 |
10 | public T GetValue(Func getter)
11 | {
12 | if (HasValue) return Value;
13 | Value = getter();
14 | HasValue = true;
15 | return Value;
16 | }
17 |
18 | public void Reset()
19 | {
20 | HasValue = false;
21 | Value = default!;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Utilities/ReadOnlyHashSet.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace IntelliTect.Coalesce.Utilities
7 | {
8 | public readonly struct ReadOnlyHashSet : IReadOnlyCollection
9 | where T : notnull
10 | {
11 | private readonly ConcurrentHashSet set;
12 |
13 | internal ReadOnlyHashSet(ConcurrentHashSet set)
14 | {
15 | this.set = set;
16 | }
17 |
18 | public int Count => set.Count;
19 |
20 | public IEnumerator GetEnumerator() => set.GetEnumerator();
21 |
22 | IEnumerator IEnumerable.GetEnumerator() => set.GetEnumerator();
23 |
24 | public bool Contains(T? item) => set.Contains(item);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IntelliTect.Coalesce/Validation/ValidationResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace IntelliTect.Coalesce.Validation
7 | {
8 | internal class ValidationResult
9 | {
10 | public bool WasSuccessful { get; set; }
11 | public bool IsWarning { get; set; }
12 | public string? Area { get; set; }
13 | public string? Message { get; set; }
14 |
15 | public bool IsError => !WasSuccessful && !IsWarning;
16 |
17 | public override string ToString()
18 | {
19 | if (WasSuccessful)
20 | {
21 | return $" Success: {Area}: {Message}";
22 | }
23 | if (IsWarning)
24 | {
25 | return $"-- Warning: {Area}: {Message}";
26 | }
27 | return $"** Failure: {Area}: {Message}";
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 11
4 | not dead
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.ts,*.vue,*.scss]
2 | indent_style = space
3 | indent_size = 2
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | "plugin:vue/essential",
8 | "eslint:recommended",
9 | "@vue/eslint-config-typescript",
10 | ],
11 | rules: {
12 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
13 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
14 | "@typescript-eslint/no-unused-vars": "error",
15 | "no-unused-vars": "off",
16 | "no-case-declarations": "off",
17 | "no-undef": "off", // Redundant with Typescript
18 | },
19 | ignorePatterns: ["lib", "dist", "node_modules"],
20 | };
21 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | #build outputs
5 | !/dist
6 | /dist/*
7 | !/dist/cjs
8 | /dist/cjs/*
9 | !/dist/cjs/package.json
10 |
11 | /lib/*
12 | !/lib/cjs
13 | /lib/cjs/*
14 | !/lib/cjs/package.json
15 |
16 | # local env files
17 | .env.local
18 | .env.*.local
19 |
20 | # Log files
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | # Editor directories and files
26 | .idea
27 | .vscode
28 | *.suo
29 | *.ntvs*
30 | *.njsproj
31 | *.sln
32 | *.sw?
33 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/README.md:
--------------------------------------------------------------------------------
1 | # coalesce-vue-vuetify2
2 |
3 | Component library for [Coalesce](https://github.com/IntelliTect/Coalesce), using Vue 2 and Vuetify 2.
4 |
5 | Learn more about Coalesce [On GitHub](https://github.com/IntelliTect/Coalesce), or [read the documentation](https://intellitect.github.io/Coalesce/stacks/vue/coalesce-vue-vuetify/overview.html).
6 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/dist/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type": "commonjs"}
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/lib/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type": "commonjs"}
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IntelliTect/Coalesce/bbbb55fd51a58355ab296730e7b0f40f4f543ca6/src/coalesce-vue-vuetify2/public/favicon.ico
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | coalesce-vue-vuetify
9 |
10 |
11 |
12 |
13 |
14 | We're sorry but coalesce-vue-vuetify doesn't work properly without JavaScript enabled. Please enable it to continue.
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/build.ts:
--------------------------------------------------------------------------------
1 | /** Component name resolver for unplugin-vue-components. */
2 |
3 | let moduleName: Promise;
4 | export function CoalesceVuetifyResolver() {
5 | moduleName = (async () => {
6 | // See if coalesce-vue-vuetify2 was aliased in package.json as coalesce-vue-vuetify.
7 | // We have to do so in a way that will work in both ESM and CJS.
8 |
9 | if ("require" in global) {
10 | try {
11 | require.resolve("coalesce-vue-vuetify");
12 | return "coalesce-vue-vuetify";
13 | } catch {
14 | /* not cjs */
15 | }
16 | } else {
17 | try {
18 | if (await import.meta.resolve?.("coalesce-vue-vuetify"))
19 | return "coalesce-vue-vuetify";
20 | } catch {
21 | /* not esm */
22 | }
23 | }
24 | return "coalesce-vue-vuetify2";
25 | })();
26 |
27 | return {
28 | type: "component",
29 | resolve: async (name: string) => {
30 | if (name.match(/^C[A-Z]/))
31 | return { name, from: (await moduleName) + "/lib" };
32 | },
33 | } as const;
34 | }
35 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/components/input/c-input-props-provider.vue:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/components/input/c-list-pagination.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
30 |
31 |
39 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/index.dist.ts:
--------------------------------------------------------------------------------
1 | /** index.dist.ts is a non-treeshakable version of coalesce-vue-vuetify,
2 | * intended for use with the non-treeshakable version of vuetify (e.g. non `/lib` import.) */
3 |
4 | import { PluginObject } from "vue";
5 |
6 | import BasePlugin, { CoalesceVuetifyOptions } from "./index";
7 | import * as components from "./components";
8 |
9 | const Plugin = >{
10 | install(Vue, options) {
11 | Vue.use(BasePlugin, options);
12 |
13 | for (const key in components) {
14 | const component = (components as any)[key];
15 | Vue.component(key, component as typeof Vue);
16 | }
17 | },
18 | };
19 |
20 | import "./shared.scss";
21 | export * from "./components";
22 | export * from "./util";
23 | export default Plugin;
24 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/index.ts:
--------------------------------------------------------------------------------
1 | /** index.ts is a treeshakable version of coalesce-vue-vuetify,
2 | * intended for use with the treeshakable version of vuetify (e.g. `vuetify/lib` import).
3 | * It does not register its own components globally, requiring use of techniques like
4 | * unplugin-vue-components (or tedious manual imports, or manual global imports) in consuming projects.
5 | *
6 | */
7 |
8 | import type { PluginObject } from "vue";
9 | import type { Domain } from "coalesce-vue";
10 |
11 | export interface CoalesceVuetifyOptions {
12 | /** A reference to the whole set of Coalesce-generated metadata for the application,
13 | * as exported from `metadata.g.ts`, e.g. `import metadata from '@/metadata.g'`. */
14 | readonly metadata?: Domain;
15 | }
16 |
17 | declare module "vue/types/vue" {
18 | export interface Vue {
19 | readonly $coalesce: CoalesceVuetifyOptions;
20 | }
21 | }
22 |
23 | const Plugin = >{
24 | install(Vue, options) {
25 | Vue.prototype.$coalesce = options ?? {};
26 | },
27 | };
28 |
29 | import "./shared.scss";
30 | export * from "./components";
31 | export * from "./util";
32 | export default Plugin;
33 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": true,
5 | "paths": {
6 | "coalesce-vue": ["../coalesce-vue/src"],
7 | "coalesce-vue/*": ["../coalesce-vue/src/*"]
8 | }
9 | },
10 | "include": ["src/**/*"]
11 | }
12 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify2/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "experimentalDecorators": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "paths": {
15 | "@/*": ["src/*"],
16 | "coalesce-vue": ["../coalesce-vue/src"],
17 | "coalesce-vue/*": ["../coalesce-vue/src/*"],
18 | "vue": ["node_modules/vue"],
19 | "vue/*": ["node_modules/vue/*"]
20 | },
21 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
22 | "types": ["node", "vuetify", "vue-router"]
23 | },
24 | "include": [
25 | "rollup.config.ts",
26 | "src/**/*.ts",
27 | "src/**/*.tsx",
28 | "src/**/*.vue",
29 | "tests/**/*.ts",
30 | "tests/**/*.tsx"
31 | ],
32 | "exclude": ["node_modules"]
33 | }
34 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.ts,*.tsx,*.vue,*.scss]
2 | indent_style = space
3 | indent_size = 2
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | "plugin:vue/vue3-essential",
8 | "eslint:recommended",
9 | "@vue/eslint-config-typescript",
10 | ],
11 | parserOptions: {
12 | ecmaVersion: "latest",
13 | },
14 | rules: {
15 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
16 | "no-useless-escape": "off",
17 | "no-case-declarations": "off",
18 | "no-console": "off",
19 | "vue/no-mutating-props": "off", // Falsely reports for mutating children of props
20 | "no-undef": "off", // Redundant with Typescript
21 | },
22 | ignorePatterns: ["dist", "node_modules"],
23 | };
24 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | #build outputs
5 | !/dist
6 | /dist/*
7 | !/dist/cjs
8 | /dist/cjs/*
9 | !/dist/cjs/package.json
10 |
11 | /lib/*
12 | !/lib/cjs
13 | /lib/cjs/*
14 | !/lib/cjs/package.json
15 |
16 | # local env files
17 | .env.local
18 | .env.*.local
19 |
20 | # Log files
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | # Editor directories and files
26 | .idea
27 | .vscode
28 | *.suo
29 | *.ntvs*
30 | *.njsproj
31 | *.sln
32 | *.sw?
33 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/README.md:
--------------------------------------------------------------------------------
1 | # coalesce-vue-vuetify3
2 |
3 | Component library for [Coalesce](https://github.com/IntelliTect/Coalesce), using Vue 3 and Vuetify 3.
4 |
5 | Learn more about Coalesce [On GitHub](https://github.com/IntelliTect/Coalesce), or [read the documentation](https://intellitect.github.io/Coalesce/stacks/vue/coalesce-vue-vuetify/overview.html).
6 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/build.ts:
--------------------------------------------------------------------------------
1 | import { existsSync, readFileSync } from "node:fs";
2 |
3 | /** Component name resolver for unplugin-vue-components that resolves coalesce-vue-vuetify3 components. */
4 | export function CoalesceVuetifyResolver() {
5 | // Read the actual component names from the source code
6 | // so that we can never have a false match.
7 | const componentExports = ["./components/index.d.ts", "./components/index.ts"]
8 | .map((f) => new URL(f, import.meta.url))
9 | .filter(existsSync)
10 | .map((f) => readFileSync(f, { encoding: "utf-8" }))[0];
11 |
12 | const components = new Set(componentExports.match(/C[A-Z][A-Za-z]+/g));
13 |
14 | return {
15 | type: "component",
16 | resolve: (name: string) => {
17 | if (components.has(name)) return { name, from: "coalesce-vue-vuetify3" };
18 | },
19 | } as const;
20 | }
21 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/components/admin/c-admin-editor.spec.tsx:
--------------------------------------------------------------------------------
1 | import { Person } from "@test-targets/models.g";
2 | import { CAdminEditor } from "..";
3 | import {
4 | PersonViewModel,
5 | PersonListViewModel,
6 | } from "@test-targets/viewmodels.g";
7 |
8 | describe("CAdminEditor", () => {
9 | test("types", () => {
10 | const model = new Person();
11 | const vm = new PersonViewModel();
12 | const list = new PersonListViewModel();
13 |
14 | () => ;
15 | //@ts-expect-error plain model not allowed
16 | () => ;
17 | //@ts-expect-error list not allowed
18 | () => ;
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/components/admin/c-admin-methods.spec.tsx:
--------------------------------------------------------------------------------
1 | import { CAdminMethods } from "..";
2 | import {
3 | PersonViewModel,
4 | PersonListViewModel,
5 | WeatherServiceViewModel,
6 | } from "@test-targets/viewmodels.g";
7 |
8 | describe("CAdminMethods", () => {
9 | test("types", () => {
10 | const vm = new PersonViewModel();
11 | const listVm = new PersonListViewModel();
12 | const serviceVm = new WeatherServiceViewModel();
13 |
14 | const rename = vm.$metadata.methods.rename;
15 |
16 | () => ;
17 | () => ;
18 | () => ;
19 |
20 | // @ts-expect-error not a model
21 | () => ;
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/components/input/c-input.spec.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | foo: {{ isActive.value }}
6 |
7 |
8 | {{
9 | (() => {
10 | //@ts-expect-error item.raw is enum metadata, cast to string should be invalid
11 | item.item.raw as string;
12 |
13 | return item.item.raw.displayName as string;
14 | })()
15 | }}
16 |
17 |
18 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/components/input/c-list-pagination.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
30 |
31 |
39 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/components/input/c-select-many-to-many.spec.tsx:
--------------------------------------------------------------------------------
1 | import { CSelectManyToMany } from "..";
2 | import { CaseViewModel } from "@test-targets/viewmodels.g";
3 |
4 | describe("CSelectManyToMany", () => {
5 | // prettier-ignore
6 | test("types", () => {
7 | const caseVm = new CaseViewModel();
8 |
9 | () => ;
10 | () => (
11 |
15 | );
16 |
17 | //@ts-expect-error wrong type
18 | () => ;
19 | () => (
20 | //@ts-expect-error wrong type
21 |
22 | );
23 |
24 | //@ts-expect-error missing `model`
25 | () => ;
26 | //@ts-expect-error missing `for`
27 | () => ;
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/composables/useMetadata.ts:
--------------------------------------------------------------------------------
1 | import { inject } from "vue";
2 | import { Domain } from "coalesce-vue";
3 |
4 | export const metadataKey = Symbol("coalesce metadata");
5 |
6 | export function useMetadata() {
7 | return inject(metadataKey) as Domain;
8 | }
9 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/env.d.ts:
--------------------------------------------------------------------------------
1 | // ///
2 |
3 | declare module "*.vue" {
4 | import type { DefineComponent } from "vue";
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>;
7 | export default component;
8 | }
9 |
10 | // declare module 'vuetify'
11 | // declare module 'vuetify/lib/components'
12 | // declare module 'vuetify/lib/directives'
13 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/src/index.ts:
--------------------------------------------------------------------------------
1 | import "./shared.scss";
2 | export * from "./components";
3 | export * from "./util";
4 | export * from "./install";
5 | export { useMetadata } from "./composables/useMetadata";
6 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/tsconfig.build-types.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "declaration": true,
6 | "emitDeclarationOnly": true,
7 |
8 | // Type checking is done according to tsconfig.json,
9 | // which is configured to be able to use coalesce-vue internal types.
10 |
11 | // However, we must emit the types using the build copy of coalesce-vue
12 | // so that typescript doesn't also emit types for coalesce-vue.
13 | // We have to turn off typechecking to do this because
14 | // the @internal types in coalesce-vue aren't available there.
15 | "noCheck": true,
16 |
17 | "rootDir": "./src",
18 | "paths": {
19 | "coalesce-vue": ["../coalesce-vue/lib"],
20 | "coalesce-vue/*": ["../coalesce-vue/lib/*"],
21 | "coalesce-vue/lib/*": ["../coalesce-vue/lib/*"]
22 | }
23 | },
24 | "include": ["src/index.ts"]
25 | }
26 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/tsconfig.build-utils.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "NodeNext",
4 | "target": "ESNext",
5 | "outDir": "./dist",
6 | "declaration": true,
7 | "skipLibCheck": true,
8 | "moduleResolution": "NodeNext"
9 | },
10 | "include": ["src/build.ts"],
11 | "exclude": ["node_modules"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/coalesce-vue-vuetify3/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2021",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "jsxImportSource": "vue",
8 | "importHelpers": true,
9 | "moduleResolution": "node",
10 | "sourceMap": true,
11 | "skipLibCheck": true,
12 | "resolveJsonModule": true,
13 | "allowSyntheticDefaultImports": true,
14 | "baseUrl": ".",
15 | "paths": {
16 | "@test/*": ["test/*"],
17 | "@test-targets/*": ["../test-targets/*"],
18 | "coalesce-vue": ["../coalesce-vue/src"],
19 | "coalesce-vue/*": ["../coalesce-vue/src/*"],
20 | "coalesce-vue/lib/*": ["../coalesce-vue/src/*"],
21 | "vue": ["node_modules/vue"],
22 | "vue/*": ["node_modules/vue/*"],
23 | "vue-router": ["node_modules/vue-router"]
24 | },
25 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
26 | "types": ["node", "vue-router", "vuetify", "vitest/globals"]
27 | },
28 | "include": [
29 | "vite.config.ts",
30 | "src/**/*.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "test/**/*.ts",
34 | "test/**/*.tsx"
35 | ],
36 | "exclude": ["node_modules"]
37 | }
38 |
--------------------------------------------------------------------------------
/src/coalesce-vue/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{vue,ts,js}]
2 | indent_style = space
3 | indent_size = 2
4 |
5 |
6 | [*.cs]
7 |
--------------------------------------------------------------------------------
/src/coalesce-vue/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.tgz
3 | lib/**/*.js
4 | lib/**/*.ts
5 | *.results.xml
--------------------------------------------------------------------------------
/src/coalesce-vue/.vscode/launch.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | // Use IntelliSense to learn about possible Node.js debug attributes.
4 | // Hover to view descriptions of existing attributes.
5 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "type": "pwa-node",
10 | "request": "launch",
11 | "name": "Debug Current Test File",
12 | "autoAttachChildProcesses": true,
13 | "skipFiles": ["/**"],
14 | "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
15 | "args": ["run", "${relativeFile}"],
16 | "smartStep": true,
17 | "console": "integratedTerminal",
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/src/coalesce-vue/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnPaste": false,
3 | "editor.formatOnSave": true,
4 | "editor.formatOnType": true,
5 | "editor.defaultFormatter": "esbenp.prettier-vscode",
6 | "prettier.useEditorConfig": false,
7 | "typescript.tsdk": "node_modules\\typescript\\lib",
8 | "[typescript]": {
9 | "editor.insertSpaces": true,
10 | "editor.tabSize": 2,
11 | "editor.autoIndent": "advanced"
12 | },
13 | "workbench.colorCustomizations": {
14 | "titleBar.activeBackground": "#a82e1f",
15 | "titleBar.inactiveBackground": "#a82e1f99",
16 | "titleBar.activeForeground": "#e7e7e7",
17 | "titleBar.inactiveForeground": "#e7e7e799"
18 | },
19 | "peacock.color": "#d33a27"
20 | }
--------------------------------------------------------------------------------
/src/coalesce-vue/README.md:
--------------------------------------------------------------------------------
1 | # coalesce-vue
2 |
3 | Core Vue library for [Coalesce](https://github.com/IntelliTect/Coalesce), supporting both Vue 2 and Vue 3.
4 |
5 | Learn more about Coalesce [On GitHub](https://github.com/IntelliTect/Coalesce), or [read the documentation](https://intellitect.github.io/Coalesce/stacks/vue/overview.html).
6 |
--------------------------------------------------------------------------------
/src/coalesce-vue/lib/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type": "commonjs"}
--------------------------------------------------------------------------------
/src/coalesce-vue/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./metadata.js";
2 | export * from "./model.js";
3 | export * from "./api-client.js";
4 | export * from "./viewmodel.js";
5 | export * from "./util.js";
6 |
--------------------------------------------------------------------------------
/src/coalesce-vue/test/global-setup.ts:
--------------------------------------------------------------------------------
1 | // Importing @vue/test-utils will turn off the Vue devtools and productionTip warnings.
2 | // Normally we could do this ourselves, but in order for this project to be a vue2/vue3 polyglot,
3 | // we have to check that we're running vue2 before we try to turn these flags off.
4 | // If we use `IsVue2` from our own util.ts file, this then makes there be a second async import
5 | // after we import from 'vue', which gives the setTimeout(..., 0) function in Vue that prints
6 | // these warnings time to run before we're able to actually turn the warnings off.
7 | // So, to make things easy, we just let the default functionality in @vue/test-utils turn them off.
8 | import "@vue/test-utils";
9 |
10 | import { version } from "vue";
11 |
12 | declare const TEST_EXPECTED_VUE_VERSION: number;
13 |
14 | expect(TEST_EXPECTED_VUE_VERSION).toBe(+version.charAt(0));
15 |
--------------------------------------------------------------------------------
/src/coalesce-vue/test/utils.spec.vue2.ts:
--------------------------------------------------------------------------------
1 | import { bindToQueryString } from "../src";
2 | import Vue from "vue";
3 |
4 | describe("VueInstance", () => {
5 | test("is assignable from Vue class component", async () => {
6 | class MyComponent extends Vue {
7 | created() {
8 | bindToQueryString(this, { a: 1 }, "a");
9 | }
10 | }
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/src/coalesce-vue/tsconfig.build.cjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib/cjs",
5 | "module": "commonjs",
6 | "target": "es2018",
7 | "verbatimModuleSyntax": false
8 | },
9 | "include": ["src/**/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/src/coalesce-vue/tsconfig.build.esm.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib",
5 | "module": "es2022",
6 | "target": "es2022"
7 | },
8 | "include": ["src/**/*"]
9 | }
10 |
--------------------------------------------------------------------------------
/src/coalesce-vue/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true,
4 | "emitDecoratorMetadata": true,
5 | "importHelpers": true,
6 | "downlevelIteration": true,
7 | "verbatimModuleSyntax": true,
8 |
9 | "noImplicitOverride": true,
10 | "strict": true,
11 | "skipLibCheck": true,
12 | "stripInternal": true,
13 |
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "target": "ES2022",
17 | "declaration": true,
18 | "lib": ["es2015", "es2017", "dom", "ES2021.WeakRef"],
19 | "types": ["vitest/globals", "vue-router"],
20 |
21 | "paths": {
22 | "@test-targets/*": ["../test-targets/*"],
23 | "coalesce-vue/lib/*": ["./src/*"]
24 | }
25 | },
26 |
27 | "exclude": ["node_modules"],
28 | "include": ["src/**/*", "test/**/*"]
29 | }
30 |
--------------------------------------------------------------------------------
/src/coalesce-vue/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, UserConfig } from "vitest/config";
2 | import path from "path";
3 |
4 | export default defineConfig({
5 | define: {
6 | TEST_EXPECTED_VUE_VERSION: 2,
7 | },
8 | test: {
9 | globals: true,
10 | environment: "jsdom",
11 | setupFiles: ["test/global-setup.ts"],
12 | include: ["**/*.{test,spec}.{ts,js}", "**/*.{test,spec}.vue2.{ts,js}"],
13 | },
14 | resolve: {
15 | alias: [
16 | // Imports inside the generated test targets:
17 | { find: "coalesce-vue/lib", replacement: path.resolve(__dirname, "src") },
18 | {
19 | find: "@test-targets",
20 | replacement: path.resolve(__dirname, "../test-targets"),
21 | },
22 | ],
23 | },
24 | }) as UserConfig;
25 |
--------------------------------------------------------------------------------
/src/coalesce-vue/vue3-tests/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "coalesce-vue3",
3 | "version": "0.1.0-local",
4 | "description": "Development only package for coalesce-vue for Vue3. Runs tests for vue3 against the polyglot package coalesce-vue. This exists because we have to install conflicting versions of vue, vue-router, and test-utils. NPM still enforces peerDependencies even when using aliased package names, which prevents us from installing them as aliases in the parent project.",
5 | "type": "module",
6 | "private": true,
7 | "scripts": {
8 | "build": "tsc",
9 | "test": "vitest",
10 | "coverage": "vitest --coverage"
11 | },
12 | "devDependencies": {
13 | "vue": "3.4.19",
14 | "vue-router": "4.1.6",
15 | "@vue/test-utils": "2.3.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/coalesce-vue/vue3-tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | // We only want to do TS builds for validation of type compatibility with vue3, not for emitting.
5 | "noEmit": true,
6 | "paths": {
7 | "@vue/test-utils": ["./node_modules/@vue/test-utils"],
8 | "vue": ["./node_modules/vue"],
9 | "vue-router": ["./node_modules/vue-router"],
10 |
11 | // For test-targets files:
12 | "@test-targets/*": ["../../test-targets/*"],
13 | "coalesce-vue/lib/*": ["../src/*"]
14 | }
15 | },
16 |
17 | "include": ["../src/**/*", "../test/**/*"],
18 | "exclude": ["../test/**/*.spec.vue2.ts"]
19 | }
20 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | Test.Template.Instance/
7 | bin/
8 | obj/
9 | *.nupkg
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dotnet.defaultSolution": "content\\Coalesce.Starter.Vue.sln",
3 | "editor.formatOnSave": true,
4 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/README.md:
--------------------------------------------------------------------------------
1 | # Coalesce Vue Template
2 |
3 |
4 | This template will set up a new Coalesce Vue solution which you can build your app upon.
5 |
6 | For instructions and additional information, visit [the Coalesce Documentation](https://intellitect.github.io/Coalesce/stacks/vue/getting-started.html).
7 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.{vue,ts,tsx,csproj,props,json,html,scss}]
4 | indent_style = space
5 | indent_size = 2
6 |
7 | [*.cs]
8 | indent_style = space
9 | indent_size = 4
10 | csharp_style_namespace_declarations=file_scoped:suggestion
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/.gitattributes:
--------------------------------------------------------------------------------
1 | *.g.cs linguist-generated=true
2 | *.g.ts linguist-generated=true
3 | auto-imports.d.ts linguist-generated=true
4 | components.d.ts linguist-generated=true
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "streetsidesoftware.code-spell-checker",
8 | "dbaeumer.vscode-eslint",
9 | "vue.volar",
10 | "esbenp.prettier-vscode",
11 | "antfu.goto-alias"
12 | ],
13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
14 | "unwantedRecommendations": []
15 | }
16 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "Coalesce.Starter.Vue.Web\\node_modules\\typescript\\lib",
3 | "dotnet.defaultSolution": "Coalesce.Starter.Vue.sln",
4 | "editor.formatOnSave": true,
5 | "editor.codeActionsOnSave": {
6 | "source.fixAll.eslint": "explicit"
7 | },
8 | "cSpell.words": ["Vite", "unplugin", "iconsets", "viewmodels", "composables"]
9 | }
10 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data.Test/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Test;
2 |
3 | public class UnitTest1 : TestBase
4 | {
5 | [Fact]
6 | public void Test1()
7 | {
8 | #if ExampleModel
9 | // Arrange
10 | var widget1 = new Widget { Name = "Gnoam Sprecklesprocket", Category = WidgetCategory.Sprecklesprockets };
11 | Db.Add(widget1);
12 | Db.SaveChanges();
13 |
14 | RefreshServices();
15 |
16 | // Act
17 | var widget2 = Db.Widgets.Single();
18 |
19 | // Assert
20 | Assert.Equal(WidgetCategory.Sprecklesprockets, widget2.Category);
21 |
22 | // After calling RefreshServices, we have a different DbContext instance
23 | // and so we'll get a different entity instance.
24 | Assert.NotEqual(widget1, widget2);
25 | #endif
26 | }
27 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Auth/AppClaimTypes.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data;
2 |
3 | public static class AppClaimTypes
4 | {
5 | public const string Role = "role";
6 | public const string Permission = "perm";
7 | public const string UserId = "sub";
8 | public const string UserName = "username";
9 | public const string Email = "email";
10 | public const string FullName = "name";
11 | #if Tenancy
12 | public const string TenantId = "tid";
13 | #endif
14 | }
15 |
16 | #if Tenancy
17 | public static class AppClaimValues
18 | {
19 | public const string GlobalAdminRole = "GlobalAdmin";
20 | public const string NullTenantId = "00000000-0000-0000-0000-000000000000";
21 | }
22 | #endif
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Auth/DbContextFactoryExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Auth;
2 |
3 | public static class DbContextFactoryExtensions
4 | {
5 | public static IEnumerable GetTenantIds(this IDbContextFactory factory)
6 | {
7 | using var db = factory.CreateDbContext();
8 |
9 | return db.Tenants.Select(t => t.TenantId).ToList();
10 | }
11 |
12 | public static AppDbContext CreateDbContext(this IDbContextFactory factory, string tenantId)
13 | {
14 | var db = factory.CreateDbContext();
15 | db.TenantId = tenantId;
16 | return db;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Auth/Permission.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data;
2 |
3 | ///
4 | /// The permissions available for assignment to s.
5 | /// Permissions generally describe actions that a user can take within the application,
6 | /// while roles are usually representative of a job title or function.
7 | ///
8 | public enum Permission
9 | {
10 | // Note: Enum values/numbers are not used for persistance - roles are stored as strings in the database.
11 |
12 | [Display(Name = "Admin - General", Description = "Modify application configuration and other administrative functions excluding user/role management.")]
13 | Admin = 1,
14 |
15 | [Display(Name = "Admin - Users", Description = "Add and modify users accounts and their assigned roles. Edit roles and their permissions.")]
16 | UserAdmin,
17 |
18 | ViewAuditLogs
19 | }
20 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Auth/UserInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Auth;
2 |
3 | public class UserInfo
4 | {
5 | public string? Id { get; set; }
6 |
7 | public string? UserName { get; set; }
8 |
9 | #if Identity
10 | public string? Email { get; set; }
11 | public string? FullName { get; set; }
12 |
13 | public required ICollection Roles { get; set; }
14 | public required ICollection Permissions { get; set; }
15 | #endif
16 | #if Tenancy
17 | [MaxLength(36)]
18 | public string? TenantId { get; set; }
19 | public string? TenantName { get; set; }
20 | #endif
21 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Auth/UserInvitation.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Auth;
2 |
3 | public class UserInvitation
4 | {
5 | public required string TenantId { get; set; }
6 |
7 | public required string Email { get; set; }
8 |
9 | public required DateTimeOffset Issued { get; set; }
10 |
11 | public required string[] Roles { get; set; }
12 | }
13 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Coalesce/AppBehaviors.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Coalesce;
2 |
3 | public abstract class AppBehaviors : StandardBehaviors
4 | where T : class
5 | {
6 | protected AppBehaviors(CrudContext context) : base(context)
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Coalesce/AppDataSource.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Coalesce;
2 |
3 | public abstract class AppDataSource : StandardDataSource
4 | where T : class
5 | {
6 | protected AppDataSource(CrudContext context) : base(context)
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Communication/AzureEmailOptions.cs:
--------------------------------------------------------------------------------
1 | using Azure.Identity;
2 |
3 | namespace Coalesce.Starter.Vue.Data.Communication;
4 |
5 | public class AzureEmailOptions
6 | {
7 | ///
8 | /// The ACS resource endpoint, e.g. "https://my-acs-resource.unitedstates.communication.azure.com".
9 | /// This code is configured to use managed RBAC authentication via
10 | /// and so does not use a connection string or API keys. Assign the Contributor role to allow email sending.
11 | ///
12 | public string? Endpoint { get; set; }
13 |
14 | public string? SenderEmail { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Communication/IEmailService.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Communication;
2 |
3 | public interface IEmailService
4 | {
5 | Task SendEmailAsync(string to, string subject, string htmlMessage);
6 | }
7 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Communication/NoOpEmailService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Hosting;
2 |
3 | namespace Coalesce.Starter.Vue.Data.Communication;
4 |
5 | public class NoOpEmailService(
6 | IHostEnvironment env
7 | ) : IEmailService
8 | {
9 | public Task SendEmailAsync(string to, string subject, string htmlMessage)
10 | {
11 | if (env.IsProduction())
12 | {
13 | throw new NotImplementedException("Email sending has not been implemented.");
14 | }
15 |
16 | // When email sending has not been implemented, dump the email content into the result message
17 | // so that essential functions during initial development (e.g. account setup links)
18 | // can still be used.
19 |
20 | return Task.FromResult(new ItemResult(true,
21 | $"DEVEOPMENT ONLY: Email sending is not configured, or is disabled by configuration. " +
22 | $"The following content would have been sent to {to}:\n\n{htmlMessage}\n\n"));
23 | }
24 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Communication/SendGridEmailOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Communication;
2 |
3 | public class SendGridEmailOptions
4 | {
5 | public string? ApiKey { get; set; }
6 |
7 | public string? SenderEmail { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/DevelopmentAppDbContextFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Design;
3 |
4 | namespace Coalesce.Starter.Vue.Data;
5 |
6 | public class DevelopmentAppDbContextFactory : IDesignTimeDbContextFactory
7 | {
8 | public AppDbContext CreateDbContext(string[] args)
9 | {
10 | // This is only used when adding migrations and updating the database from the cmd line.
11 | // It shouldn't ever be used in code where it might end up running in production.
12 | var builder = new DbContextOptionsBuilder();
13 | builder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=Coalesce.Starter.Vue;Trusted_Connection=True;TrustServerCertificate=True;");
14 | return new AppDbContext(builder.Options);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using IntelliTect.Coalesce;
2 | global using IntelliTect.Coalesce.DataAnnotations;
3 | global using IntelliTect.Coalesce.Models;
4 | global using Microsoft.EntityFrameworkCore;
5 | global using Microsoft.Extensions.Logging;
6 | global using System.ComponentModel.DataAnnotations;
7 | global using System.ComponentModel.DataAnnotations.Schema;
8 | global using static IntelliTect.Coalesce.DataAnnotations.SecurityPermissionLevels;
9 | global using System.Security.Claims;
10 | global using Coalesce.Starter.Vue.Data.Auth;
11 | global using Coalesce.Starter.Vue.Data.Coalesce;
12 | global using Coalesce.Starter.Vue.Data.Utilities;
13 | #if (Identity || ExampleModel || TrackingBase)
14 | global using Coalesce.Starter.Vue.Data.Models;
15 | #endif
16 |
17 | global using OrderByDirections = IntelliTect.Coalesce.DataAnnotations.DefaultOrderByAttribute.OrderByDirections;
18 | global using SearchMethods = IntelliTect.Coalesce.DataAnnotations.SearchAttribute.SearchMethods;
19 | global using HttpMethod = IntelliTect.Coalesce.DataAnnotations.HttpMethod;
20 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Models/Tenancy/ITenanted.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Models;
2 |
3 | ///
4 | /// The model belongs to a tenant and should be filtered to the tenant of the current user/HTTP request.
5 | ///
6 | public interface ITenanted
7 | {
8 | string TenantId { get; set; }
9 | Tenant? Tenant { get; set; }
10 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Models/Tenancy/TenantMembership.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Models;
2 |
3 | [Index(nameof(UserId), nameof(TenantId), IsUnique = true)]
4 | [InternalUse]
5 | public class TenantMembership : TenantedBase
6 | {
7 | [MaxLength(36)]
8 | public string TenantMembershipId { get; set; } = Guid.NewGuid().ToString();
9 |
10 | [Required]
11 | public string UserId { get; set; } = default!;
12 | public User? User { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Models/Tenancy/TenantedBase.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Models;
2 |
3 | public abstract class TenantedBase
4 | #if TrackingBase
5 | : TrackingBase, ITenanted
6 | #else
7 | : ITenanted
8 | #endif
9 | {
10 | [InternalUse, Required, MaxLength(36)]
11 | public string TenantId { get; set; } = null!;
12 | [InternalUse]
13 | public Tenant? Tenant { get; set; }
14 | }
15 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Models/UserPhoto.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Models;
2 |
3 | [InternalUse]
4 | [Index(nameof(UserId), IsUnique = true)]
5 | public class UserPhoto
6 | #if TrackingBase
7 | : TrackingBase
8 | #endif
9 | {
10 | public int UserPhotoId { get; set; }
11 |
12 | public required string UserId { get; set; }
13 | public User? User { get; set; }
14 |
15 | public required byte[] Content { get; set; }
16 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Models/Widget.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Coalesce.Starter.Vue.Data.Models;
4 |
5 | [Description("A sample model provided by the Coalesce template. Remove this when you start building your real data model.")]
6 | public class Widget
7 | #if Tenancy
8 | : TenantedBase
9 | #elif TrackingBase
10 | : TrackingBase
11 | #endif
12 | {
13 | public int WidgetId { get; set; }
14 |
15 | public required string Name { get; set; }
16 |
17 | public required WidgetCategory Category { get; set; }
18 |
19 | public DateTimeOffset? InventedOn { get; set; }
20 | }
21 |
22 | public enum WidgetCategory
23 | {
24 | Whizbangs,
25 | Sprecklesprockets,
26 | Discombobulators,
27 | }
28 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Data/Utilities/QueryableExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Coalesce.Starter.Vue.Data.Utilities;
2 |
3 | public static class QueryableExtensions
4 | {
5 | #if Tenancy
6 | ///
7 | /// Perform an untracked query without any tenant filtering.
8 | ///
9 | public static IQueryable IgnoreTenancy(this IQueryable query)
10 | where T : class
11 | => query.IgnoreQueryFilters().AsNoTrackingWithIdentityResolution();
12 | #endif
13 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "streetsidesoftware.code-spell-checker",
8 | "dbaeumer.vscode-eslint",
9 | "vue.volar",
10 | "esbenp.prettier-vscode",
11 | "antfu.goto-alias"
12 | ],
13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
14 | "unwantedRecommendations": []
15 | }
16 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules\\typescript\\lib",
3 | "dotnet.defaultSolution": "../Coalesce.Starter.Vue.sln",
4 | "dotnet.automaticallyCreateSolutionInWorkspace": false,
5 | "editor.formatOnSave": true,
6 | "editor.codeActionsOnSave": {
7 | "source.fixAll.eslint": "explicit"
8 | },
9 | "cSpell.words": ["Vite", "unplugin", "iconsets", "viewmodels", "composables"]
10 | }
11 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/ConfirmEmail.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model Coalesce.Starter.Vue.Web.Pages.ConfirmEmailModel
3 | @{
4 | ViewData["Title"] = "Confirm email";
5 | }
6 |
7 |
8 |
9 | @if (ModelState.IsValid)
10 | {
11 | Thank you for confirming your email.
12 |
13 |
18 | }
19 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/CreateTenant.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model Coalesce.Starter.Vue.Web.Pages.CreateTenantModel
3 |
4 | @{
5 | ViewData["Title"] = "New Organization";
6 | }
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/ExternalLogin.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ExternalLoginModel
3 | @{
4 | ViewData["Title"] = "Sign In";
5 | }
6 |
7 |
8 | @if (!string.IsNullOrWhiteSpace(Model.ErrorMessage))
9 | {
10 |
11 | @Model.ErrorMessage
12 |
13 |
14 |
19 | }
20 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/ForgotPassword.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model Coalesce.Starter.Vue.Web.Pages.ForgotPasswordModel
3 | @{
4 | ViewData["Title"] = "Forgot password";
5 | }
6 |
7 | @if (Model.Success)
8 | {
9 |
10 | If an account matching your input was found, a message with password reset instructions will be sent to the account's email address.
11 |
12 |
13 |
18 | }
19 | else
20 | {
21 |
31 | }
32 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/Invitation.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model Coalesce.Starter.Vue.Web.Pages.InvitationModel
3 | @{
4 | ViewData["Title"] = "Join Organization";
5 | }
6 |
7 |
8 |
9 | @if (ModelState.IsValid)
10 | {
11 |
12 | You have been invited to join the @Model.Tenant.Name organization. You will join as @User.GetUserName() .
13 |
14 |
15 |
21 |
22 |
28 |
29 |
34 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/SignOut.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @using Microsoft.AspNetCore.Authentication
3 | @model Coalesce.Starter.Vue.Web.Pages.SignOutModel
4 |
5 | @{
6 | ViewData["Title"] = "Sign Out";
7 | }
8 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/SignOut.cshtml.cs:
--------------------------------------------------------------------------------
1 | using Coalesce.Starter.Vue.Data.Models;
2 | using Microsoft.AspNetCore.Identity;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace Coalesce.Starter.Vue.Web.Pages;
7 |
8 | public class SignOutModel(SignInManager signInManager) : PageModel
9 | {
10 | public async Task OnGet()
11 | {
12 | await signInManager.SignOutAsync();
13 | return Redirect("/");
14 | }
15 |
16 | public async Task OnPost()
17 | {
18 | await signInManager.SignOutAsync();
19 | return Redirect("/");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Coalesce.Starter.Vue.Data.Auth
2 | @using Coalesce.Starter.Vue.Web.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Pages/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout.cshtml";
3 | }
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Kestrel": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 |
7 | // Disables injection of MSFT's undesirable JS that force-refreshes the page when C# files are changed.
8 | "hotReloadEnabled": false,
9 |
10 | "environmentVariables": {
11 | "ASPNETCORE_ENVIRONMENT": "Development"
12 | },
13 | "applicationUrl": "https://localhost:5001"
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IntelliTect/Coalesce/bbbb55fd51a58355ab296730e7b0f40f4f543ca6/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/public/favicon.ico
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/public/microsoft-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IntelliTect/Coalesce/bbbb55fd51a58355ab296730e7b0f40f4f543ca6/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/assets/logo.png
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/components/HelloWorld.spec.ts:
--------------------------------------------------------------------------------
1 | import { mount } from "@/test-utils";
2 | import HelloWorld from "./HelloWorld.vue";
3 |
4 | describe("HelloWorld.vue", () => {
5 | it("renders props.msg when passed", () => {
6 | const msg = "new message";
7 | const wrapper = mount(HelloWorld, {
8 | props: { msg },
9 | });
10 | expect(wrapper.text()).toMatch(msg);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/composables/useForm.ts:
--------------------------------------------------------------------------------
1 | import { VForm } from "vuetify/components";
2 |
3 | /** Returns a ref suitable for holding an instance of a Vuetify VForm.
4 | *
5 | * @param eagerValidate If true (default), the form will be eagerly validated,
6 | * showing error messages immediately instead of waiting for submission
7 | * or an explicit validate() call.
8 | */
9 | export function useForm(eagerValidate = true) {
10 | const form = ref();
11 |
12 | // Eagerly validate as new controls are added or removed.
13 | if (eagerValidate) {
14 | watch(
15 | () => JSON.stringify(form.value?.items.map((i) => i.id)),
16 | () => {
17 | form.value?.validate();
18 | },
19 | );
20 | }
21 |
22 | return form;
23 | }
24 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/composables/useUser.ts:
--------------------------------------------------------------------------------
1 | import {
2 | userInfo,
3 | //#if Identity
4 | can,
5 | //#endif
6 | } from "@/user-service";
7 |
8 | export function useUser() {
9 | return {
10 | userInfo,
11 | //#if Identity
12 | can,
13 | //#endif
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/styles/site.scss:
--------------------------------------------------------------------------------
1 | a {
2 | text-decoration: none;
3 | }
4 |
5 | // Vuetify3 lost the padding for ul/ol that Vuetify2 had. Restore it.
6 | .v-application {
7 | ul,
8 | ol {
9 | padding-left: 24px;
10 | }
11 | }
12 |
13 | // Details under inputs are bottom-aligned by default. Undo that.
14 | .v-input__details {
15 | align-items: normal;
16 | padding-top: 3px;
17 | overflow: visible;
18 | }
19 |
20 | .v-icon {
21 | // Vuetify v-icon expects to be inline-flex,
22 | // but fontawesome defaults to inline-block through this var.
23 | // Without setting this, icon appearance can vary with CSS load order
24 | --fa-display: inline-flex;
25 | }
26 |
27 | // Visually distinguish readonly inputs
28 | .v-input--readonly {
29 | .v-switch__track,
30 | .v-switch__thumb {
31 | border: 1px dashed rgba(var(--v-theme-on-surface), 0.7);
32 | }
33 | .v-field__outline__start,
34 | .v-field__outline__end,
35 | .v-field__outline__notch::before,
36 | .v-field__outline__notch::after {
37 | border-style: dashed;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/types/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | declare global {
5 | declare const BUILD_DATE: Date | null | undefined;
6 | declare const ASPNETCORE_ENVIRONMENT: string;
7 | }
8 |
9 | export {};
10 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/views/OpenAPI.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
17 |
18 |
19 |
20 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/views/WidgetEdit.spec.ts:
--------------------------------------------------------------------------------
1 | import { mount, flushPromises, mockEndpoint } from "@/test-utils";
2 |
3 | import { VTextField } from "vuetify/components";
4 | import WidgetEdit from "./WidgetEdit.vue";
5 | import { Widget, WidgetCategory } from "@/models.g";
6 |
7 | describe("WidgetEdit.vue", () => {
8 | it("loads user id 1", async () => {
9 | // Arrange
10 | mockEndpoint("/Widget/get", () => ({
11 | wasSuccessful: true,
12 | object: {
13 | widgetId: 1,
14 | name: "Whirlygig",
15 | category: WidgetCategory.Sprecklesprockets,
16 | } as Widget,
17 | }));
18 |
19 | // Act
20 | const wrapper = mount(WidgetEdit, { props: { id: 1 } });
21 | await flushPromises();
22 |
23 | // Assert
24 | expect(wrapper.text()).toMatch("Editing Widget: 1");
25 | expect(document.title).toMatch("Whirlygig");
26 | expect(wrapper.findComponent(VTextField).vm.modelValue).toBe("Whirlygig");
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/src/views/errors/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "moduleResolution": "node",
8 | "incremental": true,
9 | "tsBuildInfoFile": "./node_modules/.tsbuildinfo",
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "allowSyntheticDefaultImports": true,
13 | "noEmit": true,
14 | "baseUrl": ".",
15 | "paths": {
16 | "@/*": ["src/*"]
17 | }
18 | },
19 | "include": [
20 | "src/**/*.ts",
21 | "src/**/*.tsx",
22 | "src/**/*.vue",
23 | "tests/**/*.ts",
24 | "tests/**/*.tsx"
25 | ],
26 | "references": [{ "path": "./tsconfig.node.json" }]
27 | }
28 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "types": ["node", "vitest"]
7 | },
8 | "include": ["vite.config.ts"],
9 | "exclude": ["node_modules"]
10 | }
11 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Coalesce.Starter.Vue.Web/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 12.0
4 | true
5 | enable
6 |
7 | true
8 |
9 | 5.3.2
10 |
11 |
12 | $(DefineConstants);KeepTemplateOnly;AppInsights;OpenAPI;AuditLogs;TrackingBase;ExampleModel
13 | $(DefineConstants);Identity;UserPictures;MicrosoftAuth;GoogleAuth;LocalAuth
14 | $(DefineConstants);EmailAzure;EmailSendGrid
15 | $(DefineConstants);Tenancy;TenantPerHostname;TenantCreateSelf;TenantCreateExternal;TenantCreateAdmin;TenantMemberInvites
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/templates/Coalesce.Vue.Template/content/coalesce.json:
--------------------------------------------------------------------------------
1 | {
2 | "webProject": {
3 | "projectFile": "./Coalesce.Starter.Vue.Web/Coalesce.Starter.Vue.Web.csproj"
4 | },
5 | "dataProject": {
6 | "projectFile": "./Coalesce.Starter.Vue.Data/Coalesce.Starter.Vue.Data.csproj"
7 | },
8 |
9 | "rootGenerator": "Vue",
10 |
11 | "generatorConfig": {
12 | "Scripts": {
13 | "targetDirectory": "../src"
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------