Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fluffy-toys-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baseplate-dev/react-generators': patch
---

Remove @headlessui/react package
5 changes: 5 additions & 0 deletions .changeset/rare-pandas-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baseplate-dev/plugin-auth': patch
---

Support validating users on admin app based off their roles
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ export function buildTsProjectExportMap(
}) ?? [];

// Figure out the default import provider
const importProviderNames = getDefaultImportProviderNames(generatorName);
const importProviderNames = getDefaultImportProviderNames(
generatorName,
config.defaultImportProviderName,
);

const relativeGeneratorDirectory = path.relative(
packagePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@ export interface TsImportProviderNames {
* Gets the names of the default import provider.
*
* @param generatorName - The name of the generator.
* @param defaultImportProviderName - The name of the default import provider if provided.
* @returns The names of the import provider.
*/
export function getDefaultImportProviderNames(
generatorName: string,
defaultImportProviderName: string | undefined,
): TsImportProviderNames {
const parsedGeneratorName = parseGeneratorName(generatorName);
const { generatorBasename } = parsedGeneratorName;
const generatorBasename =
defaultImportProviderName?.replace(/ImportsProvider$/, '') ??
parsedGeneratorName.generatorBasename;
const providerTypeName = `${pascalCase(generatorBasename)}ImportsProvider`;
const providerExportName = `${camelCase(generatorBasename)}ImportsProvider`;
const providerSchemaName = `${camelCase(generatorBasename)}ImportsSchema`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ export function renderTsImportProviders(
generatorBarrelExports: TemplateExtractorGeneratedBarrelExport[];
}
| undefined {
const importProviderNames = getDefaultImportProviderNames(generatorName);
const importProviderNames = getDefaultImportProviderNames(
generatorName,
extractorConfig?.defaultImportProviderName,
);

const projectExportArray = templates.flatMap((template) =>
Object.entries(template.config.projectExports ?? {}).map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ export const tsExtractorConfigSchema = z
* Always specified as package-name:provider-name
*/
importProviders: z.array(z.string()).optional(),
/**
* Optional, the name of the default import provider to use (must end with 'ImportsProvider'). Defaults to the generator name with ImportsProvider suffix.
*/
defaultImportProviderName: z
.string()
.endsWith('ImportsProvider')
.optional(),
/**
* Optional, whether to skip the default import map generation
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"importMapProviders": {},
"pathRootRelativePath": "{module-root}/constants/auth-roles.constants.ts",
"projectExports": {
"AUTH_ROLE_CONFIG": {},
"AuthRole": { "isTypeOnly": true },
"DEFAULT_PUBLIC_ROLES": {},
"DEFAULT_USER_ROLES": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { AUTH_AUTH_ROLES_PATHS } from './template-paths.js';

const authRolesImportsSchema = createTsImportMapSchema({
AUTH_ROLE_CONFIG: {},
AuthRole: { isTypeOnly: true },
DEFAULT_PUBLIC_ROLES: {},
DEFAULT_USER_ROLES: {},
Expand All @@ -35,6 +36,7 @@ const authAuthRolesImportsTask = createGeneratorTask({
return {
providers: {
authRolesImports: createTsImportMap(authRolesImportsSchema, {
AUTH_ROLE_CONFIG: paths.authRoles,
AuthRole: paths.authRoles,
DEFAULT_PUBLIC_ROLES: paths.authRoles,
DEFAULT_USER_ROLES: paths.authRoles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const authRoles = createTsTemplateFile({
importMapProviders: {},
name: 'auth-roles',
projectExports: {
AUTH_ROLE_CONFIG: {},
AuthRole: { isTypeOnly: true },
DEFAULT_PUBLIC_ROLES: {},
DEFAULT_USER_ROLES: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"authContextImportsProvider": {
"importName": "authContextImportsProvider",
"packagePathSpecifier": "@baseplate-dev/fastify-generators:src/generators/auth/auth-context/generated/ts-import-providers.ts"
},
"authRolesImportsProvider": {
"importName": "authRolesImportsProvider",
"packagePathSpecifier": "@baseplate-dev/fastify-generators:src/generators/auth/auth-roles/generated/ts-import-providers.ts"
}
},
"pathRootRelativePath": "{module-root}/types/user-session.types.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { typescriptFileProvider } from '@baseplate-dev/core-generators';
import { createGeneratorTask, createProviderType } from '@baseplate-dev/sync';

import { authContextImportsProvider } from '#src/generators/auth/auth-context/generated/ts-import-providers.js';
import { authRolesImportsProvider } from '#src/generators/auth/auth-roles/generated/ts-import-providers.js';

import { AUTH_USER_SESSION_TYPES_PATHS } from './template-paths.js';
import { AUTH_USER_SESSION_TYPES_TEMPLATES } from './typed-templates.js';
Expand All @@ -30,13 +31,14 @@ const authUserSessionTypesRenderers =
const authUserSessionTypesRenderersTask = createGeneratorTask({
dependencies: {
authContextImports: authContextImportsProvider,
authRolesImports: authRolesImportsProvider,
paths: AUTH_USER_SESSION_TYPES_PATHS.provider,
typescriptFile: typescriptFileProvider,
},
exports: {
authUserSessionTypesRenderers: authUserSessionTypesRenderers.export(),
},
run({ authContextImports, paths, typescriptFile }) {
run({ authContextImports, authRolesImports, paths, typescriptFile }) {
return {
providers: {
authUserSessionTypesRenderers: {
Expand All @@ -47,6 +49,7 @@ const authUserSessionTypesRenderersTask = createGeneratorTask({
destination: paths.userSessionTypes,
importMapProviders: {
authContextImports,
authRolesImports,
},
...options,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { createTsTemplateFile } from '@baseplate-dev/core-generators';
import path from 'node:path';

import { authContextImportsProvider } from '#src/generators/auth/auth-context/generated/ts-import-providers.js';
import { authRolesImportsProvider } from '#src/generators/auth/auth-roles/generated/ts-import-providers.js';

const userSessionTypes = createTsTemplateFile({
fileOptions: { kind: 'singleton' },
importMapProviders: { authContextImports: authContextImportsProvider },
importMapProviders: {
authContextImports: authContextImportsProvider,
authRolesImports: authRolesImportsProvider,
},
name: 'user-session-types',
projectExports: {
UserSessionPayload: { isTypeOnly: true },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// @ts-nocheck

import type { AuthUserSessionInfo } from '%authContextImports';
import type { AuthRole } from '%authRolesImports';
import type { FastifyReply, FastifyRequest } from 'fastify';

export interface UserSessionPayload {
userId: string;
expiresAt: Date;
roles: readonly AuthRole[];
}

export interface UserSessionService {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { typescriptFileProvider } from '@baseplate-dev/core-generators';
import { createGenerator, createGeneratorTask } from '@baseplate-dev/sync';
import { z } from 'zod';

import { authContextImportsProvider } from '../auth-context/index.js';
import { AUTH_USER_SESSION_TYPES_GENERATED } from './generated/index.js';

const descriptorSchema = z.object({});
Expand All @@ -14,25 +12,15 @@ export const userSessionTypesGenerator = createGenerator({
buildTasks: () => ({
paths: AUTH_USER_SESSION_TYPES_GENERATED.paths.task,
imports: AUTH_USER_SESSION_TYPES_GENERATED.imports.task,
renderers: AUTH_USER_SESSION_TYPES_GENERATED.renderers.task,
main: createGeneratorTask({
dependencies: {
typescriptFile: typescriptFileProvider,
paths: AUTH_USER_SESSION_TYPES_GENERATED.paths.provider,
authContextImports: authContextImportsProvider,
renderers: AUTH_USER_SESSION_TYPES_GENERATED.renderers.provider,
},
run({ typescriptFile, paths, authContextImports }) {
run({ renderers }) {
return {
build: async (builder) => {
await builder.apply(
typescriptFile.renderTemplateFile({
template:
AUTH_USER_SESSION_TYPES_GENERATED.templates.userSessionTypes,
destination: paths.userSessionTypes,
importMapProviders: {
authContextImports,
},
}),
);
await builder.apply(renderers.userSessionTypes.render({}));
},
};
},
Expand Down
3 changes: 0 additions & 3 deletions packages/project-builder-lib/src/schema/apps/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
export * from './backend/index.js';
export * from './base.js';
export * from './types.js';
// Re-export admin types from web admin for backward compatibility
export * from './web/admin/index.js';

export * from './web/index.js';
1 change: 1 addition & 0 deletions packages/project-builder-lib/src/schema/apps/web/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './admin/index.js';
export * from './web-app.js';
10 changes: 0 additions & 10 deletions packages/project-builder-lib/src/schema/apps/web/web-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { z } from 'zod';

import type { def } from '#src/schema/creator/index.js';

import { authRoleEntityType } from '#src/schema/auth/index.js';
import { definitionSchema } from '#src/schema/creator/schema-creator.js';

import { baseAppValidators } from '../base.js';
Expand All @@ -16,15 +15,6 @@ export const createWebAppSchema = definitionSchema((ctx) =>
includeAuth: ctx.withDefault(z.boolean(), false),
title: z.string().default(''),
description: z.string().default(''),
allowedRoles: ctx.withDefault(
z.array(
ctx.withRef({
type: authRoleEntityType,
onDelete: 'DELETE',
}),
),
[],
),
includeUploadComponents: ctx.withDefault(z.boolean(), false),
enableSubscriptions: ctx.withDefault(z.boolean(), false),
adminApp: createAdminAppSchema(ctx),
Expand Down
6 changes: 5 additions & 1 deletion packages/project-builder-server/src/compiler/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function buildAdminRoutes(
builder: AppEntryBuilder<WebAppConfig>,
): GeneratorBundle | undefined {
const { adminApp } = builder.appConfig;
const { projectDefinition } = builder;
const { projectDefinition, definitionContainer } = builder;

if (!adminApp?.enabled) {
return undefined;
Expand Down Expand Up @@ -93,6 +93,10 @@ function buildAdminRoutes(
]
: []),
],
requiredRoles:
adminApp.allowedRoles?.map((roleId) =>
definitionContainer.nameFromId(roleId),
) ?? [],
}),
admin: adminHomeGenerator({}),
adminRoutes: backendApp.enableBullQueue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type {

import {
Alert,
AlertDescription,
AlertTitle,
Button,
Dialog,
DialogContent,
Expand Down Expand Up @@ -99,7 +101,10 @@ export function EmbeddedListInput<InputType>({
},
})
) : (
<Alert variant="default">No items currently</Alert>
<Alert variant="default">
<AlertTitle>No items currently</AlertTitle>
<AlertDescription>Add an item to get started.</AlertDescription>
</Alert>
)}
<Dialog
open={!!valueToEdit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@baseplate-dev/ui-components';
import { zodResolver } from '@hookform/resolvers/zod';
import { useNavigate } from '@tanstack/react-router';
import { sortBy } from 'es-toolkit';
import { sortBy, startCase } from 'es-toolkit';
import { useForm } from 'react-hook-form';

import { logAndFormatError } from '#src/services/error-formatter.js';
Expand Down Expand Up @@ -55,7 +55,6 @@ function NewAppDialog({
const appTypeOptions = [
{ label: 'Backend App', value: 'backend' },
{ label: 'Web App', value: 'web' },
{ label: 'Admin App', value: 'admin' },
];

const onSubmit = handleSubmit((data) => {
Expand All @@ -67,6 +66,10 @@ function NewAppDialog({
{
...data,
id: newId,
...(data.type === 'web' && {
title: startCase(data.name),
description: `A ${data.type} application`,
}),
},
];
draftConfig.apps = sortBy(newApps, [(app) => app.name]) as AppConfig[];
Expand Down Expand Up @@ -122,7 +125,7 @@ function NewAppDialog({
control={control}
name="type"
options={appTypeOptions}
description="Backend apps provide APIs, web apps are client applications, and admin apps manage data"
description="Backend apps provide APIs, web apps are client applications"
/>
<DialogFooter>
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
useResettableForm,
} from '@baseplate-dev/project-builder-lib/web';
import {
Badge,
Button,
ComboboxFieldController,
FormActionBar,
Expand Down Expand Up @@ -229,7 +228,7 @@ function WebAdminPage(): React.JSX.Element {
</div>
</RecordViewItem>
<RecordViewItem title="Type">
<Badge variant="secondary">{section.type}</Badge>
{section.type}
</RecordViewItem>
<RecordViewItem title="Icon">
{section.icon ?? (
Expand Down Expand Up @@ -317,6 +316,7 @@ function WebAdminPage(): React.JSX.Element {
label="Name"
control={sectionFormProps.control}
name="name"
autoComplete="off"
/>
<ComboboxFieldController
label="Feature"
Expand Down
Loading