diff --git a/Source/DotNET/Model/Packages/ScenePackage.cs b/Source/DotNET/Model/Packages/ScenePackage.cs index a86db6a..a018694 100644 --- a/Source/DotNET/Model/Packages/ScenePackage.cs +++ b/Source/DotNET/Model/Packages/ScenePackage.cs @@ -23,6 +23,16 @@ namespace Cratis.Scene.Model.Packages; /// The module that implements the package - an npm package name for a web renderer. Design-time tooling /// needs it to know what to import; the model itself never loads anything. /// +/// +/// The license the package is available under, as a short human-readable name (MIT, +/// PrimeUI Community). A package picker shows it, because "what am I taking on by selecting this" +/// is a question an author needs answered before they select it, not after. +/// +/// +/// Where the license terms actually live, so a reader can go and check rather than take +/// on trust. Required in practice for anything that is not a permissive +/// standard license - a name alone tells an author nothing about eligibility or obligations. +/// public record ScenePackage( string Name, string Version, @@ -35,4 +45,6 @@ public record ScenePackage( IReadOnlyList Themes, string? DisplayName = null, string? Description = null, - string? Module = null); + string? Module = null, + string? License = null, + string? LicenseUrl = null); diff --git a/Source/DotNET/Model/Profiles/Theme.cs b/Source/DotNET/Model/Profiles/Theme.cs index 3dcc76f..9bc706e 100644 --- a/Source/DotNET/Model/Profiles/Theme.cs +++ b/Source/DotNET/Model/Profiles/Theme.cs @@ -23,6 +23,7 @@ namespace Cratis.Scene.Model.Profiles; /// /// A link to the original creator or the theme's home, shown alongside . /// The license the theme is used under, so redistributing it stays honest. +/// Where those license terms live, so a reader can check them rather than take on trust. /// A one-line description for a theme picker. public record Theme( string Name, @@ -32,4 +33,5 @@ public record Theme( string? Author = null, string? AuthorUrl = null, string? License = null, - string? Description = null); + string? Description = null, + string? LicenseUrl = null); diff --git a/Source/JavaScript/blueprint.components/componentsBlueprint.ts b/Source/JavaScript/blueprint.components/componentsBlueprint.ts index 44e8941..c645ecc 100644 --- a/Source/JavaScript/blueprint.components/componentsBlueprint.ts +++ b/Source/JavaScript/blueprint.components/componentsBlueprint.ts @@ -49,6 +49,8 @@ export const componentsBlueprintManifest: ScenePackage = { displayName: 'Cratis Components Blueprint', description: 'Arc-bound screen and dialog templates: whole pages built from the Cratis Components composites, for the default blueprint shell.', module: '@cratis/scene.blueprint.components', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/blueprint.default/defaultBlueprint.ts b/Source/JavaScript/blueprint.default/defaultBlueprint.ts index b9f79ab..be42f47 100644 --- a/Source/JavaScript/blueprint.default/defaultBlueprint.ts +++ b/Source/JavaScript/blueprint.default/defaultBlueprint.ts @@ -42,6 +42,8 @@ export const defaultBlueprintManifest: ScenePackage = { displayName: 'Cratis Default Blueprint', description: 'Application shells with eight menu modes, the components that fill their slots, and a full screen and dialog template set.', module: '@cratis/scene.blueprint.default', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/components/cratisComponentsPackage.ts b/Source/JavaScript/components/cratisComponentsPackage.ts index be46fcb..d7fdbec 100644 --- a/Source/JavaScript/components/cratisComponentsPackage.ts +++ b/Source/JavaScript/components/cratisComponentsPackage.ts @@ -90,6 +90,8 @@ export const cratisComponentsPackageManifest: ScenePackage = { displayName: 'Cratis Components', description: "Cratis' Arc-bound data, form and dialog composites, built on PrimeReact and Tailwind.", module: '@cratis/scene.components', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/model/packages/ScenePackage.ts b/Source/JavaScript/model/packages/ScenePackage.ts index 9e6e3ae..9a92ba8 100644 --- a/Source/JavaScript/model/packages/ScenePackage.ts +++ b/Source/JavaScript/model/packages/ScenePackage.ts @@ -72,6 +72,20 @@ export interface ScenePackage { * tooling needs it to know what to import; the model itself never loads anything. */ module?: string; + + /** + * The license the package is available under, as a short human-readable name (`MIT`, + * `PrimeUI Community`). A package picker shows it, because "what am I taking on by selecting this" + * is a question an author needs answered before they select it, not after. + */ + license?: string; + + /** + * Where the license terms actually live, so a reader can go and check rather than take `license` on + * trust. Required in practice for anything that is not a permissive standard license — a name alone + * tells an author nothing about eligibility or obligations. + */ + licenseUrl?: string; } export const ScenePackagePropertyNames: (keyof ScenePackage)[] = [ @@ -87,4 +101,6 @@ export const ScenePackagePropertyNames: (keyof ScenePackage)[] = [ 'displayName', 'description', 'module', + 'license', + 'licenseUrl', ]; diff --git a/Source/JavaScript/model/profiles/Theme.ts b/Source/JavaScript/model/profiles/Theme.ts index e4807ed..1b8368c 100644 --- a/Source/JavaScript/model/profiles/Theme.ts +++ b/Source/JavaScript/model/profiles/Theme.ts @@ -50,6 +50,11 @@ export interface Theme { * A one-line description for a theme picker. */ description?: string; + + /** + * Where those license terms live, so a reader can check them rather than take `license` on trust. + */ + licenseUrl?: string; } export const ThemePropertyNames: (keyof Theme)[] = [ @@ -61,4 +66,5 @@ export const ThemePropertyNames: (keyof Theme)[] = [ 'authorUrl', 'license', 'description', + 'licenseUrl', ]; diff --git a/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts b/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts index 44f2c2d..911d3ec 100644 --- a/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts +++ b/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts @@ -1,7 +1,7 @@ // Copyright (c) Cratis. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import { primeReactThemes } from '../theme'; +import { primeReactThemeLicense, primeReactThemeLicenseUrl, primeReactThemes } from '../theme'; describe('when checking attribution', () => { it('should credit an author on every theme', () => { @@ -27,7 +27,17 @@ describe('when checking attribution', () => { * catalog would have gone on advertising MIT indefinitely. */ it('should state the commercial license PrimeReact 11 actually ships under, not the MIT of v10', () => { - primeReactThemes.filter((theme) => theme.license !== 'PrimeUI Commercial').should.deep.equal([]); + primeReactThemeLicense.should.equal('PrimeUI Community / Commercial'); + primeReactThemes.filter((theme) => theme.license !== primeReactThemeLicense).should.deep.equal([]); + }); + + /** + * A license name on its own does not tell a reader whether they qualify for the free Community tier + * or owe a commercial fee. The link is the part that answers that, so it is pinned too. + */ + it('should link to the terms on every theme, not just name them', () => { + primeReactThemeLicenseUrl.should.equal('https://primeui.dev/licenses/community'); + primeReactThemes.filter((theme) => theme.licenseUrl !== primeReactThemeLicenseUrl).should.deep.equal([]); }); it('should describe every theme for a picker', () => { diff --git a/Source/JavaScript/primereact/primeReactPackage.ts b/Source/JavaScript/primereact/primeReactPackage.ts index eebae95..0f7307d 100644 --- a/Source/JavaScript/primereact/primeReactPackage.ts +++ b/Source/JavaScript/primereact/primeReactPackage.ts @@ -71,6 +71,11 @@ export const primeReactPackageManifest: ScenePackage = { displayName: 'PrimeReact', description: 'PrimeReact 11 components and PrimeTek\'s @primeuix/themes presets, mapped onto Scene\'s abstract component names.', module: '@cratis/scene.primereact', + // PrimeReact 11 is PrimeTek's commercial PrimeUI, not MIT as version 10 was. The Community + // tier is free for eligible projects but still requires a key, so an author selecting this + // package needs to see the terms before they select it, not after a banner appears. + license: 'PrimeUI Community / Commercial', + licenseUrl: 'https://primeui.dev/licenses/community', }; /** diff --git a/Source/JavaScript/primereact/theme/primeReactThemes.ts b/Source/JavaScript/primereact/theme/primeReactThemes.ts index a1103d2..c780e7a 100644 --- a/Source/JavaScript/primereact/theme/primeReactThemes.ts +++ b/Source/JavaScript/primereact/theme/primeReactThemes.ts @@ -41,7 +41,14 @@ export const primeReactThemeCompatibility: string[] = ['PrimeReact', 'Tailwind', * @see https://primeui.dev/licenses/community for the free community tier and its eligibility limits. * @see https://primeui.dev/licenses/commercial for the paid tier. */ -export const primeReactThemeLicense = 'PrimeUI Commercial'; +export const primeReactThemeLicense = 'PrimeUI Community / Commercial'; + +/** + * Where those terms live. A license name alone tells a reader nothing about whether they qualify for the + * free Community tier or owe a commercial fee, so the catalog carries the link rather than making them + * search for it. + */ +export const primeReactThemeLicenseUrl = 'https://primeui.dev/licenses/community'; /** * Every theme this package ships, as Scene {@link Theme}s. @@ -61,6 +68,7 @@ export const primeReactThemes: Theme[] = themePresets.map((preset) => ({ author: 'PrimeTek', authorUrl: 'https://primereact.org', license: primeReactThemeLicense, + licenseUrl: primeReactThemeLicenseUrl, })); /** diff --git a/Source/JavaScript/react/core/corePackage.ts b/Source/JavaScript/react/core/corePackage.ts index 5a5b120..17da3b4 100644 --- a/Source/JavaScript/react/core/corePackage.ts +++ b/Source/JavaScript/react/core/corePackage.ts @@ -25,6 +25,8 @@ export const corePackageManifest: ScenePackage = { displayName: 'Core', description: 'The built-in fallback vocabulary every ui profile resolves against.', module: '@cratis/scene.react', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/tailwind/tailwindPackage.ts b/Source/JavaScript/tailwind/tailwindPackage.ts index 1165cf6..cde78e5 100644 --- a/Source/JavaScript/tailwind/tailwindPackage.ts +++ b/Source/JavaScript/tailwind/tailwindPackage.ts @@ -27,6 +27,8 @@ export const tailwindPackageManifest: ScenePackage = { displayName: 'Tailwind CSS', description: 'Utility-first CSS. The styling system Cratis Components and the default layouts are written against.', module: '@cratis/scene.tailwind', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/scene-model-shape.json b/scene-model-shape.json index 1e1a988..4ba7d2a 100644 --- a/scene-model-shape.json +++ b/scene-model-shape.json @@ -191,7 +191,8 @@ "author", "authorUrl", "license", - "description" + "description", + "licenseUrl" ], "PackageDependency": [ "name", @@ -209,7 +210,9 @@ "themes", "displayName", "description", - "module" + "module", + "license", + "licenseUrl" ], "Screen": [ "name",