mirror of
https://github.com/ever-co/ever-gauzy.git
synced 2026-10-02 01:54:50 +08:00
* feat(plugin-subscription-access): add access control and user assignment
Implement a comprehensive system for managing plugin subscription access,
including hierarchical subscriptions, user assignment, and revocation.
This introduces:
- Parent-child subscription relationships in PluginSubscription entity,
enabling organization/tenant-level subscriptions to manage individual
user access.
- Commands, handlers, DTOs, and API endpoints for assigning and revoking
plugin access to users.
- A dedicated PluginSubscriptionAccessService for centralized validation
of user access, assignment permissions, and subscription details.
- A PluginSubscriptionAccessGuard for protecting plugin routes based on
subscription status.
- Refinements to the subscription purchase logic to automatically set
USER scope for free plans and handle initial statuses (ACTIVE, PENDING, TRIAL).
* feat(plugins-access): implement plugin subscription access management
Introduce a robust system for managing and controlling access to plugins based on subscriptions. This includes:
- New Akita state management (store, query, facade) to track plugin and user-specific access.
- Dedicated service for API interactions (check, assign, revoke access, bulk checks).
- UI dialogs (PluginUserAssignmentDialogComponent, PluginUserRevocationDialogComponent) for managing user assignments and revocations.
- An Angular guard (PluginAccessGuard) to protect plugin routes and prompt for subscription if needed.
- Updates to the plugin marketplace item to display access levels and enable user assignment actions.
- Extend plugin subscription plans to support various access scopes (user, organization, tenant, global).
- Add component for displaying plugin subscription hierarchy.
* feat: Implement subscription management for plugin installations
- Refactored plugin installation logic to handle subscription-based plugins.
- Introduced strategies for free and subscription-based plugin installations.
- Added validation chain for installation prerequisites, including access and subscription checks.
- Created a facade for managing installation processes and strategies.
- Implemented access guard to verify user permissions for plugin installations.
- Enhanced UI components to reflect subscription requirements during installation.
- Added validators for plugin status and subscription requirements.
- Improved error handling and user notifications for subscription-related actions.
* feat(plugin-tenant): add PluginTenantService for managing plugin-tenant relationships
* refactor(plugin-marketplace): remove analytics tracking from various actions
* feat(plugin-subscription): add ability to upgrade and downgrade plans
Introduce new functionality for users to change their active plugin
subscription plans. This includes new Redux actions and effects for
managing the upgrade and downgrade processes, alongside new API
endpoints to handle these requests on the backend.
The plugin subscription selection dialog has been enhanced to:
* Detect and display the user's current active subscription plan.
* Visually distinguish the current plan, making it unselectable.
* Dynamically update the primary action button to reflect "Upgrade
Plan", "Downgrade Plan", or "Current Plan" based on the selected
plan and the user's existing subscription status.
* Implement client-side logic to determine the appropriate plan
change type (upgrade or downgrade) based on plan hierarchy.
* feat(plugin-installation): streamline plugin removal by simplifying parameters
* feat(plugin-marketplace): implement lazy loaded detail tabs
Refactor plugin marketplace item detail page to use NbRouteTabset with lazy-loaded child routes.
This improves initial load performance by only loading tab content when activated.
New tabs introduced:
* Settings: Configure plugin-specific options (permission-gated).
* User Management: Assign and unassign users to the plugin (permission-gated).
Existing "Overview" and "Source Code" tab content has been extracted into dedicated lazy-loaded components to align with this new structure.
Tabs are dynamically rendered based on user permissions for configuration and assignment.
* feat(plugin-user-management): implement user assignment facade and dialogs
Introduce PluginUserAssignmentFacade to centralize business logic and
provide a simplified API for managing plugin user assignments. This
enhances testability, maintainability, and improves reactive data flow.
Refactor PluginUserAssignmentEffects to include:
- Comprehensive loading state management for all assignment operations.
- Translateable success and error notifications using ToastrNotificationService.
- Direct store updates on success (add, remove, set assignments).
- Flexible loading of assignments for a plugin or specific installation.
Add showAssignmentDialog, hideAssignmentDialog, showRevocationDialog, and
hideRevocationDialog effects in PluginSubscriptionAccessEffects to
orchestrate UI dialogs for user assignment and revocation.
Update UserManagementTabComponent to consume the new
PluginUserAssignmentFacade via a consolidated view model. This reduces
component complexity, simplifies template logic, and ensures proper
handling of loading and error states in the UI.
* feat(plugin-installation): return structured response for install and uninstall
The `create` and `remove` endpoints for plugin installation and
uninstallation now return a structured JSON response. Previously,
these methods returned `void`, providing no body on success.
This change enhances client feedback by including a descriptive
message and the HTTP status code in the response body.
* feat(plugins-registry): return paginated results for plugin user assignments
Update query handlers and service methods related to plugin user assignments
to return `IPagination<PluginUserAssignment>` instead of a plain array.
This standardizes list retrieval operations by providing pagination metadata.
Also, correct the instantiation of `TypeOrmPluginUserAssignmentRepository`
to properly inject and utilize the underlying TypeORM repository.
BREAKING CHANGE: Plugin user assignment query handlers and service methods
now return an IPagination object instead of a plain array. Consumers
expecting an array will need to adapt to the new return structure (e.g.,
accessing `result.items`).
* feat(plugins): add infinite scroll and pagination for user assignments
This commit introduces infinite scroll functionality to the plugin user assignment lists, significantly enhancing the user experience and performance when dealing with a large number of assigned users.
Key changes include:
- A new `InfiniteScrollDirective` in `desktop-ui-lib` to detect scroll events and emit `scrolled` events.
- Implementation of `take` and `skip` based pagination across plugin user assignment APIs (frontend and backend) and state management (Akita store, query, facade, effects). This forms the foundation for efficient data loading.
- Refactoring of plugin user assignment, unassignment, and access check mechanisms to utilize a subscription-based access control model. This involves changes to service methods and API endpoints, promoting a more scalable and consistent approach to managing plugin access.
The combined changes allow for lazy loading of user assignments, reducing initial load times and memory footprint.
* refactor(plugin-user-assignment): update user interface and improve state selectors
* feat(plugin-user-management): implement available users state management and infinite scroll
Introduces a dedicated Akita state management module (`_available-users` store, query, effects) for handling the list of users available for plugin assignment. This refactors the user fetching, filtering, and selection logic, improving separation of concerns and maintainability.
The `PluginUserManagementComponent` has been refactored to utilize a new `UserManagementFacade`, which orchestrates interactions between the available users and plugin user assignment state.
Key changes include:
- Added `AvailableUsersActions`, `AvailableUsersEffects`, `AvailableUsersQuery`, `AvailableUsersStore` for robust state management.
- Created `UserManagementFacade` to provide a high-level, component-agnostic API for user management.
- Refactored `PluginUserManagementComponent` to delegate all business logic to the `UserManagementFacade`.
- Implemented infinite scroll for the "Available Users" list, enhancing UX for large user bases.
- Updated `plugins.module` to include new state management providers and the `InfiniteScrollDirective`.
- Adjusted `UserManagementTabComponent` to clear and reload assignments after unassignment for improved data consistency.
* refactor(plugin-user-management): reorder initialization methods in ngOnInit for better clarity
* chore(plugin-marketplace): update store config names
Rename store configuration names to use snake_case instead of
kebab-case. This change ensures consistent naming conventions
across the application's state management modules. Additionally,
the 'plugin-user-assignment' store name has been pluralized to
'plugin_user_assignments' for improved semantic clarity.
* fix(plugin-marketplace): correct total count for available users
Remove client-side pagination logic and derive the total count
for available users directly from the API response. This ensures
that the displayed total accurately reflects the backend's
pagination and overall count, preventing data inconsistencies.
Also add a debug log to `loadAssignmentsSuccess` for better visibility.
* refactor: streamline effects in plugin subscription access and user assignment
- Updated effects in `plugin-subscription-access.effects.ts` for better readability and consistency.
- Added dispatch options to effects where necessary.
- Removed unused imports in `plugin-subscription.effect.ts`.
- Refactored loading and assignment effects in `plugin-user-assignment.effects.ts` for clarity and efficiency.
- Improved error handling messages for user assignment actions.
- Cleaned up module imports in `plugins.module.ts` for better organization.
* feat(i18n): enhance plugin user management with new loading states and action messages
* feat(plugins): enhance plugin subscription access and activation flow
Introduce `IPluginAccess` contract and `PluginScope` enum to standardize plugin access details across the platform.
Implement server-side validation for plugin activation and deactivation, ensuring that actions are authorized before local execution. This improves security and adherence to subscription rules.
Refine `PluginSubscriptionAccessService.getSubscriptionDetails` to provide comprehensive access information, including:
- Determining if a plugin requires a subscription.
- Calculating `canAssign` and `canActivate` permissions based on subscription ownership and user assignments.
- Validating subscription parent relationships.
Consolidate `PluginScope` enum definition into the `@gauzy/contracts` package for better shared model management.
* feat(plugin-installation): implement multi-step workflow with installation ID
Introduce a unique installation ID and a comprehensive multi-step workflow
for managing plugin installations. This enhancement provides a robust mechanism
to track plugins across the desktop application and the server-side registry,
improving reliability and traceability of plugin lifecycle events.
Key changes include:
- Add `installationId` column to the `plugins` database table via new migration.
- Update plugin metadata interfaces, services, and the `plugin-manager` to
support storing and managing the `installationId`.
- Refactor the desktop UI's plugin installation process into distinct
steps: download, server-side registration, local completion, and activation.
- Utilize a Command Pattern for each installation step in the UI, enabling
better separation of concerns, explicit error handling, and potential for
rollback mechanisms.
- Server-side plugin installation now returns the generated `installationId`.
- New IPC channel and Electron service method `completeInstallation` added
to sync the `installationId` locally after server registration.
- Update plugin activation, deactivation, and uninstallation logic across
desktop-lib and desktop-ui-lib to explicitly use the `installationId`
for server communication.
* feat(plugins): enhance plugin lifecycle authorization and flow
This commit introduces several improvements to the plugin management
lifecycle, primarily focusing on enhanced security, authorization,
and a more robust client-side installation experience.
Key changes include:
- Enforce employee-specific authorization for plugin installation,
activation, deactivation, and uninstallation, ensuring actions are
tied to the installing employee.
- The `ActivatePluginCommand` now explicitly includes `pluginId`
alongside `installationId` for more precise control over activation.
- Client-side plugin installation completion now utilizes an event-driven
progress observable, improving monitoring and responsiveness.
- The `RequestContext.currentOrganizationId()` helper can now retrieve
the organization ID from the `organization-id` request header.
- The legacy `PluginInstallHandler` and `PluginUninstallHandler` have
been removed.
- The `PluginSubscriptionAccessGuard` now performs stricter validation
for missing plugin IDs.
* fix(plugin-marketplace): reset installing flag after plugin installation
Ensure the 'installing' flag in the plugin installation store is
explicitly set to false when an installation process finalizes.
Previously, only `completingInstallation` was reset, which could
lead to an incorrect UI state where a plugin appeared to be
stuck in an 'installing' state after completion or failure.
* feat(i18n): add strings for categories, plugin management, and user assignment
Add comprehensive internationalization strings to support new and enhanced
UI features. This includes:
* New success, error, and info messages for managing plugin categories
(CRUD, load operations).
* Messages for successful assignment/unassignment of users to plugins,
including bulk actions, and related error states.
* Expanded plugin lifecycle messages covering subscription, download, and
server installation progress.
* New confirmation and error messages for plugin source deletion and
restoration.
* Improved parameter naming for plugin version toasts (from `number` to
`version`).
* Additional generic error messages for plugin forms and data.
* refactor(plugins): streamline billing and subscription entities
Removed direct billing, pricing, invoice, and payment retry-related fields from
PluginBilling and PluginSubscription entities.
Shifted responsibility for subscription pricing, type, and billing period
to PluginSubscriptionPlan, referenced by a new planId on PluginSubscription.
Introduced computed properties (isOverdue, isPending, daysUntilDue) on
PluginBilling for derived status based on existing data.
Reimplemented nextBillingDate and isBillingDue as computed properties
on PluginSubscription, deriving their state from associated PluginBilling
records rather than stored fields.
Updated related DTOs and interfaces (IPluginBillingCreateInput,
IPluginSubscriptionCreateInput, IPluginSubscriptionPurchaseInput, etc.) to
reflect the entity simplifications and removal of redundant fields.
This refactor reduces data redundancy, improves data consistency by
centralizing billing plan details, and better encapsulates runtime state
through computed properties.
* refactor(plugins): simplify user assignments and refine setting management
Remove the dedicated `PluginUserAssignment` entity and its corresponding interfaces,
consolidating user assignment logic within the plugin subscription domain.
Update plugin user assignment handlers and services to utilize `subscriptionId`
instead of `pluginInstallationId` for clarity and consistency with the new structure.
Rework the `PluginSetting` entity:
- Store setting `value` as plain `text` instead of `jsonb`, simplifying data handling.
- Introduce a unique index on `pluginId`, `key`, and `pluginTenantId` to prevent
duplicate configurations.
- Add an `updatedById` field to track the user who last modified a setting.
- Enhance validation rules and `ApiProperty` decorations for existing fields.
- Add `ColumnIndex` decorations for improved query performance.
* refactor(plugins): simplify user assignment and subscription management
Removed `PluginUserAssignment` entity, its repositories, and related models.
Refactored plugin user assignment commands, queries, and handlers to use
`pluginId` directly instead of `pluginInstallationId`. Replaced complex
assignment logic in `PluginUserAssignmentService` with placeholder
implementations, indicating a future re-design.
Updated plugin subscription logic to utilize a `planId` for managing
subscription details (type, billing period, trial days) instead of direct
fields. Streamlined `PluginBillingService` by removing internal total amount
calculation and retry logic.
Restructured plugin user assignment API controllers and DTOs to align with
the new, simplified model, removing `installationId` from endpoints and DTOs.
This change is a preparatory step for a more robust and flexible plugin
management system.
* feat(plugins/billing): implement comprehensive plugin billing system
Introduce a new billing system for plugin subscriptions using a CQRS and
event-driven architecture. This includes:
* **Billing Commands:** Commands for creating billing records and processing
payments.
* **Command Handlers:** Logic to handle billing creation and payment
processing, integrating with a new `PluginBillingFactory`.
* **Billing Events:** Domain events for billing lifecycle states (created,
paid, failed, overdue).
* **Event Handlers:** React to billing events to update subscription metadata,
change status (e.g., suspend on multiple failures), and trigger
notifications (future implementation).
* **PluginBillingFactory:** Encapsulates business logic for creating various
types of billing records (initial, renewal, upgrade).
The `PluginSubscriptionService` is updated to utilize this new billing flow for
purchasing, renewing, and upgrading subscriptions, promoting a cleaner
separation of concerns and a more robust billing lifecycle management.
It also introduces new helper methods to determine subscription scope and
initial status based on plan type.
* feat(billing): formalize subscription billing calculations
Refactor subscription billing logic in PluginBillingFactory to extract complex
calculations into a new private method, `calculateBillingAmount`.
This centralizes the application of base price, discounts, and setup fees,
ensuring consistency and clarity. The `createForRenewal` and `createInitialBilling`
methods now accept the full plan object, simplifying their signatures and
enabling richer metadata capture.
Billing records are enhanced with detailed metadata including `basePrice`,
`discountAmount`, `setupFee`, `effectivePrice`, and a comprehensive breakdown
string, improving traceability and auditability of charges.
Explicitly clarifies that discounts and setup fees apply only to initial billing.
Extensive inline documentation has been added to the factory to outline these rules.
* feat(plugin-subscription): add subscriber for entity lifecycle management
Implement a TypeORM subscriber for `PluginSubscription` entities.
This subscriber's `afterLoad` hook automatically updates the in-memory
subscription status to `EXPIRED` if its `endDate` has passed, ensuring
the entity's state is consistent upon loading. It also logs the current
state of the subscription for debugging and monitoring.
Additionally, refactor `PluginSubscription` entity to use the
`PluginBillingStatus` enum for billing status checks, enhancing type
safety and readability.
* fix(plugin-system): always deactivate plugin before deletion
Ensure plugins are always cleanly shut down before their files and metadata are
removed, preventing potential resource leaks or orphaned processes.
Previously, deactivation was conditional on the plugin's `isActivate` metadata
flag, which could lead to improper cleanup if the metadata was out of sync or
the plugin was in an inconsistent state.
* refactor(plugin-subscriptions): consolidate domain logic and access
Transition the plugin subscription management to a rich domain model by encapsulating business rules and state changes directly within the `PluginSubscription` entity.
Introduce `PluginSubscriptionAccessService` to centralize complex access validation and permissions, leveraging Strategy and Factory patterns for modularity. This service now orchestrates access checks across different subscription scopes (user, organization, tenant).
Update the `PluginSubscriptionService` to delegate business logic to the `PluginSubscription` entity's new domain methods for operations like cancellation, renewal, upgrade, downgrade, and trial extension.
Remove the `PluginUserAssignmentService` as its responsibilities are now integrated into the centralized subscription access architecture.
Adjust consuming components, including `PluginAccessGuard`, `PluginInstallationAccessGuard`, `PluginSubscriptionGuard`, and `CheckPluginAccessQueryHandler`, to utilize the new `PluginSubscriptionAccessService` for consistent and robust access control.
This refactor improves maintainability, testability, and adherence to domain-driven design principles. Additionally, trial subscriptions are now correctly identified as active during access checks.
* feat(plugins-registry): add plugin user assignment service
Introduce a lightweight stub for the PluginUserAssignmentService. This
service provides an interface for managing user assignments to plugins,
including methods to assign, unassign, and check user access.
The current implementation is minimal, designed primarily to satisfy
imports and provide a consistent API for command and query handlers.
Full business logic and persistence will be implemented in a subsequent
iteration.
* feat(plugin-registry): implement plugin queries and handlers
- Add GetPluginQuery for fetching a plugin by ID.
- Implement CheckPluginAccessQueryHandler to validate plugin access.
- Create GetPluginQueryHandler to retrieve plugin details.
- Introduce ListPluginsQuery and ListPluginsQueryHandler for paginated plugin listing.
- Add SearchPluginsQuery and SearchPluginsQueryHandler for advanced plugin searching.
- Establish a new index for plugin queries and handlers.
- Refactor plugin subscription strategies for creating and updating subscription plans.
- Implement PluginSubscriptionGuard to ensure valid subscriptions before plugin installation.
- Update shared DTOs and models for better organization and access.
- Enhance infrastructure with new controllers, guards, and storage strategies.
* refactor: reorganize imports and exports
This commit refactors the import and export statements across
multiple files within the plugin registry package. The goal is
to improve code organization, reduce redundancy, and clarify
dependencies.
Specifically, it addresses the following:
- Consolidates exports within the `index.ts` files of the
`application`, `domain`, `infrastructure`, and `shared`
directories. This makes it easier to understand the public API
of each module.
- Reorganizes imports to use relative paths for internal modules and
absolute paths for external dependencies.
- Refactors the structure to leverage the index.ts for exporting,
reducing the lines of code.
This change doesn't introduce any functional changes but aims to
improve maintainability and readability.
* feat: Add validation for plugin settings and subscription plans
This commit enhances the plugin registry by:
- Adding validation rules for plugin setting creation and updates.
- Implementing validation and defaults for plugin subscription plans.
- Ensuring date fields in plugin subscriptions are properly converted.
- Adding default activation status for subscription plans and subscriptions.
- Allowing stringified JSON for validation rules.
* refactor: Remove unused imports and reorder imports
Removes unused imports and reorders the imports to improve
code readability and maintainability across multiple files.
* refactor: Add business logic methods to entities
Adds business logic methods to `Plugin`, `PluginVersion`,
`PluginSource`, and `PluginInstallation` entities. Also adds static
methods and interfaces to the models. These methods encapsulate
plugin-related operations such as status checks, version
comparisons, and download counts.
* refactor: use Plugin.create to instantiate plugin
Refactor the plugin instantiation to use `Plugin.create` method
instead of `Object.assign`. This aligns with the project's
intended object creation pattern.
* feat: implement plugin tenant management
This commit introduces a new feature for managing plugin tenants,
allowing for tenant-specific configurations and access controls.
The changes include:
- Added commands and queries for creating, updating, deleting,
enabling, disabling, and approving plugin tenants.
- Implemented command handlers and query handlers to process the
respective commands and queries.
- Added a controller for managing plugin tenants through API endpoints.
- Introduced DTOs for data transfer and validation.
- Updated the plugin model to remove the GLOBAL plugin scope.
- Exported plugin tenant modules.
* fix: apply fixes and improvements across plugins registry
This commit addresses several issues within the plugins registry:
- Removes redundant error message for GLOBAL plugin scope.
- Fixes module import for plugin tenants.
- Improves logic for determining subscription plan operation type.
- Ensures planId is correctly passed during subscription plan updates.
- Adds repository url to CreatePluginDTO and boolean transformation for requiresSubscription
* refactor(plugins): introduce dedicated DTO and remove client-side category counting
Introduce a new `PluginQueryOptions` DTO to provide strongly-typed
query parameters for fetching a single plugin. This replaces the
generic `BaseQueryDTO` in the `PluginController` and `GetPluginQuery`,
improving type safety and API documentation.
In the desktop UI, the client-side logic for calculating plugin category
counts (`updateCategoryCounts`) has been removed from the marketplace
filter component. This simplifies the frontend, as category counts are
now handled and delivered by the backend.
* refactor(plugins): simplify PluginSubscriptionService by removing unused methods and dependencies
* feat(subscription): add computed properties and helper methods to IPluginSubscriptionPlan interface
* refactor(plugin-subscription): move business logic into domain models
Refactor the command handlers for subscription actions (cancel, upgrade, downgrade, renew) to use a richer domain model approach.
Business logic and validation rules, previously handled within the service layer, are now encapsulated as methods directly on the subscription domain entity. Command handlers are now responsible for fetching the entity, invoking its business methods, and persisting the result.
This change aligns with Domain-Driven Design (DDD) principles, making the application layer thinner and centralizing business rules within the domain. This improves maintainability, testability, and clarity of the subscription lifecycle logic.
Additionally, the IPluginTenant interface has been extended with business logic method signatures to support this pattern more broadly.
* refactor(plugin-subscription): refactor trial extension command handler
Relocate the business logic for extending a trial subscription from the `PluginSubscriptionService` directly into the `ExtendTrialSubscriptionCommandHandler`.
This refactoring aligns with CQRS best practices by making the command handler more self-contained and responsible for its specific unit of work. The handler now fetches the subscription using the correct security context, validates the action using new domain entity methods (`canExtendTrial`, `extendTrial`), and persists the result.
This approach improves clarity, testability, and adherence to domain-driven design principles by placing business rules within the domain model itself.
As part of this cleanup, the implementation for the deprecated `PurchasePluginSubscriptionCommandHandler` has been removed.
* feat(plugin-subscription): implement plugin subscription purchase logic
This commit implements the complete logic for the
PurchasePluginSubscriptionCommandHandler. It handles the creation of
plugin subscriptions based on different scenarios, including free, trial,
and paid plans.
The handler now:
- Validates required input like plugin and tenant IDs.
- Ensures a `PluginTenant` relationship exists, creating one if needed.
- Differentiates subscription creation based on the plan type:
- Free plans result in an immediate active subscription.
- Plans with a trial period create a trial subscription.
- Paid plans create a pending subscription with a calculated end date.
- Defaults to a free subscription if no plan is specified.
- Sets additional properties like auto-renew and metadata from the DTO.
* feat(plugin-tenant): support scope on creation and set defaults
The `PluginTenantService.findOrCreate` method is updated to accept an
optional `scope` parameter. This allows callers, such as the plugin
purchase handler, to specify the installation scope (tenant,
organization, or user).
When a new `PluginTenant` relationship is created, it is now populated
with sensible defaults, including `requiresApproval: true` and
`autoInstall: false`. The `approvedById` is set to the current user
initiating the action to ensure a secure initial state.
BREAKING CHANGE: The default scope for a newly created PluginTenant
now defaults to `USER` if not explicitly provided. Previously, the scope
was inferred as `TENANT` or `ORGANIZATION` based on the presence of an
`organizationId`.
* refactor(plugin-subscription): overhaul plugin subscription and access control service
This commit completely refactors the plugin subscription and access control logic to follow Domain-Driven Design (DDD) and SOLID principles. The previous implementation was becoming difficult to maintain and extend.
Key changes include:
- Re-architected `PluginSubscriptionAccessService` to act as a true domain service.
- Introduced the Specification pattern for validating access rules (e.g., plugin enabled, subscription active, quota limits), encapsulating business logic into small, reusable components.
- Implemented a composite `AccessValidator` to orchestrate validation specifications.
- Refactored subscription finders to use a `SubscriptionFinderRegistry` with a clear Chain of Responsibility pattern (User > Organization > Tenant).
- Integrated `PluginTenant` service to manage tenant-specific configurations like installation/user quotas, approvals, and access lists.
- Rewrote multiple CQRS query handlers for subscriptions to use explicit TypeORM queries instead of high-level service methods, improving clarity and error handling. They now return empty results instead of throwing exceptions on failure.
- Simplified the `CreatePluginSubscriptionPlanCommand` to only require the DTO and the acting user's ID.
BREAKING CHANGE: The `GetPluginSubscriptionsByPluginIdQuery` and `GetPluginSubscriptionsBySubscriberIdQuery` handlers now return a paginated object `IPagination<IPluginSubscription>` instead of an array `IPluginSubscription[]`.
BREAKING CHANGE: The `CreatePluginSubscriptionPlanCommand` constructor signature has been changed, removing `tenantId` and `organizationId`.
* fix(plugin-marketplace): prevent runtime errors from non-array subscription data
The plugin marketplace could encounter runtime errors if API responses or
the internal state for subscriptions and plans were not arrays. This could
happen during initial load or with inconsistent API payloads, leading to
crashes.
This commit introduces defensive checks across the data flow:
- `PluginSubscriptionService` now normalizes API responses to ensure
methods always return an array, handling various payload structures.
- `PluginSubscriptionStore` and `PluginSubscriptionQuery` are updated to
safely handle non-array state, defaulting to an empty array for
operations like map, filter, and find.
This makes the subscription management feature more robust and resilient to
unexpected data shapes.
* feat(plugin-registry): implement plugin user access and assignment logic
This commit introduces the full implementation for the plugin user assignment feature, replacing the previous stub and placeholder logic. It provides a complete system for managing which users have access to specific plugins within a tenant and organization.
Key changes include:
- The `PluginUserAssignmentService` is fully implemented. It now manages user assignments by interacting with the `PluginTenantService` and `RoleService` to enforce access control based on user lists, roles, and quotas.
- All query handlers related to user assignments are implemented, providing real data for endpoints that list plugin assignments for a user or user assignments for a plugin.
- Pagination (`skip`, `take`) is added to all relevant query handlers and controller endpoints for fetching user assignment lists.
- Controllers are updated to use `RequestContext` to derive the current tenant and organization, ensuring operations are correctly scoped.
- `PluginSubscriptionService` now includes `createChildSubscriptions` and `revokeChildSubscriptions` methods to manage individual user subscriptions tied to a parent tenant/organization subscription.
- The `ProcessBillingCommandHandler` is simplified to use the `PluginBillingService` directly.
* feat(plugin-tenant): add pagination to get plugin-tenants queries
Adds support for pagination to the queries that retrieve plugin-tenant
relationships by either plugin ID or tenant ID.
The `GetPluginTenantsByPluginQuery` and `GetPluginTenantsByTenantQuery`
now accept optional `skip` and `take` parameters. The corresponding
controller endpoints have been updated to accept these as query
parameters, allowing clients to paginate through large result sets.
The query handlers and service methods are updated to handle these
new parameters and return a paginated response.
BREAKING CHANGE: The `/by-plugin/:pluginId` and `/by-tenant/:tenantId` endpoints now return a paginated response object of type `IPagination<IPluginTenant>` instead of a simple array.
* feat(plugin-tenant): apply plan limitations during creation
Refactor the `PluginTenantService.findOrCreate` method to accept a single
input object instead of multiple arguments. This improves readability
and makes the method easier to extend.
When purchasing a new plugin subscription, if the selected plan includes
limitations such as maximum users or installations, these values are now
passed during PluginTenant creation and stored accordingly.
Additionally, the user initiating the creation of the PluginTenant
relationship is now automatically granted access to the plugin.
* feat(plugin): set default isActive to true during plugin creation
* fix(registry): correct plugin approval and subscription checks
The `isApproved` method on the PluginTenant entity is updated to also check for the presence of `approvedById`. This makes the approval check more robust, ensuring a plugin is considered approved if it has an approver, even if the `approvedAt` timestamp is missing.
The logic for determining if a plugin requires a subscription has been refined. A new `isSubscriptionRequired` method is introduced in the plan service, which checks for active paid plans (price > 0) or if the plugin is explicitly flagged as requiring a subscription. This replaces a less accurate check and prevents free plugins from being misidentified.
* feat(plugin-subscription): implement contextual upgrade and downgrade flow
Introduce a comprehensive, state-managed subscription management flow that provides a contextual experience for users with existing subscriptions.
This change refactors the subscription selection process to be aware of the user's current plan, enabling intelligent upgrade, downgrade, and new subscription actions.
Key additions:
- A new `PlanComparisonService` encapsulates the business logic for determining action types (upgrade, downgrade), calculating prorations, and validating plan changes.
- Akita state is expanded to track the plan comparison process, confirmation steps, and current subscription/plans on a per-plugin basis.
- A new `SubscriptionConfirmationComponent` provides a clear summary of changes before the user commits.
- The subscription selection UI is significantly enhanced with:
- Skeleton loaders and improved error states.
- Visual badges and styling for upgrade/downgrade actions.
- Improved accessibility and keyboard shortcuts.
* feat(plugins): introduce subscription scope and auto-renew
This commit refactors the plugin subscription system to introduce subscription scopes (User, Organization, Tenant) and an auto-renew option. This provides more flexible subscription models and improves system robustness.
The subscription creation API payload is updated to include `scope` and `autoRenew`, while moving `billingPeriod` into the metadata object.
Frontend changes:
- Add a read-only section to display the plan's scope in the subscription dialog.
- Add an auto-renew checkbox to the subscription form.
- Automatically determine and set the subscription scope based on the selected plan type.
Backend changes:
- Add a unique database constraint (`pluginId`, `subscriberId`) to the `PluginSubscription` entity to prevent multiple subscriptions for the same user and plugin.
- Update subscription creation logic to handle pre-existing cancelled or expired subscriptions by deleting them before creating a new one.
- Refactor the `PluginSubscriptionPlan` entity with a builder pattern and static factory methods for more consistent plan creation.
* style(plugin-marketplace): enhance subscription plan selection UI
Overhauls the visual design of the plugin subscription selection screen to create a more modern, polished, and engaging user experience.
This update refines the styling for both the plan selection cards and the subscription preview component.
Key changes include:
- Redesigned `PlanCardComponent` with enhanced hover, focus, and selection states, incorporating subtle scaling, improved shadows, and smoother animations.
- Updated `SubscriptionPreviewComponent` with a cleaner layout, improved typography, and distinct styling for summary items.
- Replaced the feature list with a responsive grid of styled tags for better readability.
- Added responsive styles for improved usability on smaller screens.
- Implemented dark theme support for visual consistency.
* feat(subscription): add plan comparison and formatting services
- Implemented PlanComparisonService to handle logic for comparing subscription plans, including actions for new subscriptions, upgrades, downgrades, and current plans.
- Added methods for calculating proration amounts, checking upgrade/downgrade eligibility, and generating user-friendly action descriptions.
- Introduced PlanFormatterService for formatting subscription plan data for display, including transformation to view models and formatting prices and billing periods.
- Enhanced user experience with clear action descriptions and button variants based on plan actions.
* feat(subscription): enhance plan card comparison and update module exports
* refactor(plugins): introduce shared components and services for subscription management
This commit modularizes the plugin subscription management UI by extracting shared logic and presentation into reusable components and services. This improves code reuse, maintainability, and adherence to SOLID principles.
New shared modules have been created:
- **Shared Components:**
- `SubscriptionPlanCardComponent`: A reusable presentational component for displaying subscription plan details.
- `SubscriptionBillingFormComponent`: A component encapsulating the subscription billing form logic and UI.
- `SubscriptionStatusBadgeComponent`: A component for consistently displaying subscription status badges.
- **Shared Services:**
- `SubscriptionPlanService`: Centralizes business logic for plan comparison (upgrade/downgrade), price formatting, and savings calculations.
- `SubscriptionFormService`: Manages the creation and validation logic for the subscription form.
- `SubscriptionStatusService`: Provides helpers for mapping subscription statuses to UI elements (badges, icons).
The `PluginSubscriptionManagerComponent` has been significantly refactored to consume these new shared modules, removing duplicated logic and mock data. It is now connected to the `PluginSubscriptionFacade` to handle real subscription state changes.
Additionally, `PluginSubscriptionPlanSelectionComponent` and `PluginSubscriptionHierarchyComponent` are updated to leverage the new shared services, simplifying their implementations.
* feat: Refactor subscription plugin installation strategy and dialog routing
- Updated SubscriptionPluginInstallationStrategy to utilize SubscriptionDialogRouterService for managing subscription dialogs.
- Enhanced SubscriptionBillingFormComponent with improved UI elements and accessibility features.
- Introduced SubscriptionDialogRouterService to handle routing to appropriate subscription dialogs based on user status.
- Improved PluginAccessGuard to utilize the new dialog routing service for better user experience.
- Updated styles in subscription billing form for a more modern look and feel.
- Added animations and improved error handling in various components.
- Removed deprecated SubscriptionPlanCardComponent in favor of new plan card implementation.
* refactor(subscription): streamline subscription update input and improve upgrade/downgrade methods
* refactor: update plugin subscription plan data structure and comparison logic
* refactor(plugin-marketplace): streamline state management and improve loading states
- Updated PluginSourceEffects and PluginVersionEffects to use new state management methods for setting loading, creating, updating, deleting, and restoring states.
- Refactored PluginSourceStore and PluginVersionStore to include new methods for managing sources and versions, enhancing clarity and maintainability.
- Improved error handling and reset functionality across various stores.
- Enhanced the plugin subscription components to correctly display and manage subscription plans, including upgrades and downgrades.
- Cleaned up HTML templates for better readability and maintainability.
* refactor(plugin-marketplace): centralize state logic and add validation chain
Move state mutation logic from effects into the corresponding Akita stores. This centralizes the responsibility for merging and sorting collections of plugin versions and sources, making the effects cleaner and more focused on orchestration. The stores now handle maintaining a unique, sorted list of items.
Introduce an `InstallationValidationChainBuilder` to create a formal, extensible validation process before a plugin is installed or updated. This replaces scattered validation logic with a centralized chain of responsibility, improving robustness and maintainability. This new validation service is now used in both the item and detail components.
Additionally, this commit includes minor fixes such as:
- Using the async pipe for subscription checks in templates.
- Adding guards for potentially null values.
- Simplifying store reset logic.
* fix(subscription-manager): correct plan type display logic in subscription info
* feat(plugin): treat pending subscriptions as active and add tenant archiving
Subscriptions in a `PENDING` state are now consistently treated as active across the application. This prevents users from creating duplicate subscriptions while a payment is processing and allows them to manage their plan before it is fully activated.
This change ensures that pending subscriptions are correctly recognized when checking for an existing active subscription, calculating counts, and determining available actions like upgrades.
This also fixes a bug in the purchase handler where an existing subscription could be missed if its scope did not match the new purchase request.
Additionally, this commit introduces the ability to archive and restore plugin tenant configurations, providing a soft-delete mechanism.
* refactor(subscription-finders): update subscription retrieval logic to handle failures and adjust active status flag
* refactor(plugin-marketplace): decouple plan state from subscription state
The state management for plugin subscriptions previously handled
subscriptions, plans, and plan comparisons within a single, monolithic
Akita store. This made the state complex and difficult to maintain.
This refactoring separates these concerns into three distinct state
slices:
- PluginSubscription
- PluginPlan
- PluginPlanComparison
Each slice now has its own dedicated store, actions, effects, and
query files. The `PluginSubscriptionFacade` has been updated to act as
an orchestrator for these new, more focused state modules.
This change improves separation of concerns, enhances modularity, and
clarifies the responsibilities of each part of the plugin state.
* style(plugins): standardize code formatting and import order
Apply consistent code formatting, including indentation and import statement order, across various files in the plugin marketplace feature.
This improves code readability and maintainability without altering any functionality.
* refactor(plugin-marketplace): centralize plugin deletion confirmation logic in effect
Move the plugin deletion confirmation dialog from the components to the PluginMarketplaceEffects.
Previously, both the `PluginMarketplaceDetailComponent` and the `PluginMarketplaceItemComponent` contained identical logic to prompt the user before deleting a plugin. This refactoring centralizes this logic into a single effect.
Now, components simply dispatch the `delete` action, and the effect is responsible for showing the confirmation dialog before calling the delete service. This improves code reuse and separates concerns more cleanly.
* refactor(plugin): centralize and improve uninstallation process
The plugin uninstallation flow is overhauled to be more robust and to centralize logic within the `PluginInstallationEffects`.
The backend `uninstallPlugin` method is enhanced to find plugins by various criteria (ID, marketplace ID) and returns the `installationId`.
The frontend effect now:
- Presents a confirmation dialog to the user before proceeding.
- Uses the returned `installationId` to determine if a server-side API call is required, correctly handling both local-only and marketplace plugins.
- Centralizes the uninstallation logic, removing it from individual components.
This refactoring makes the process more reliable, improves code structure, and provides a better user experience. A new effect to check plugin installation status has also been added.
* refactor(plugin-marketplace): centralize plugin update dialog logic into effect
Move the responsibility for opening the PluginMarketplaceUploadComponent
dialog from individual components into the `update$` effect.
This simplifies `PluginMarketplaceDetailComponent` and
`PluginMarketplaceItemComponent` by removing duplicated dialog-handling
logic. Components now only dispatch the `update` action, and the effect
orchestrates the entire workflow, including user interaction and the
subsequent API call.
The `PluginMarketplaceActions.update` action signature is updated to
accept the full plugin object to facilitate this change.
* feat(plugin-marketplace): pre-select version and source on plugin update
When a user initiates an update for a plugin, the context for that
plugin (version and source) is now set in the state stores.
This ensures that when the update dialog opens, it is pre-populated
with the correct information, improving the user experience and reducing
the chance of errors.
* refactor(plugin-installation): centralize per-plugin toggle state
The previous implementation for managing a plugin's installation toggle state was flawed. It relied on a single global state object in the Akita store and additional local state within components. This could lead to state inconsistencies, especially when multiple plugin components are rendered simultaneously.
This refactoring addresses these issues by:
- Modifying the PluginInstallationStore to manage a collection of toggle states, one for each plugin, identified by `pluginId`.
- Removing local state management from `PluginMarketplaceDetailComponent` and `PluginMarketplaceItemComponent`.
- Components now query the central store for the installation status of their specific plugin.
- Encapsulating the installation check logic within an NgRx Effect, triggered by a `check` action for a more robust state flow.
- Updating actions to use `pluginId`, making state updates more precise.
- Ensuring that installation failures correctly reset the UI toggle for the specific plugin that failed.
* refactor(plugin-marketplace): centralize utility functions and dialog logic
Introduce a new `PluginMarketplaceUtilsService` to consolidate duplicated helper methods for labels, badges, and formatting across marketplace components. This eliminates code repetition and improves maintainability.
The logic for handling the creation of new plugin versions and sources is moved from the `PluginMarketplaceItemComponent` into the corresponding NgRx Effects. Effects now manage opening the creation dialogs, which centralizes side-effect handling and simplifies the component. The related `add` actions are updated to accept the `IPlugin` object directly.
* refactor(plugins): centralize PluginScope enum and remove GLOBAL scope
Move the PluginScope enum from its local definition within the
plugin-subscription-access service to the shared @gauzy/contracts
package. This ensures a single source of truth for plugin scopes across
the platform.
As part of this refactoring, the unused `PluginScope.GLOBAL` has been
completely removed from all related logic, including labels, status
indicators, and helper functions.
Additionally, this change improves type safety in the `OverviewTabComponent`
by correctly importing and using the `PluginType` enum.
* style(plugins): add explicit public access modifiers
Enforce explicit `public` access modifiers for methods and getters in plugin marketplace components and services to improve code clarity and maintain a consistent style.
Additionally, the unused `ngOnInit` lifecycle hook is removed from the `OverviewTabComponent` as part of this code cleanup.
* refactor(plugins): centralize marketplace logic into effects
Move complex business logic from plugin marketplace components into NgNeat effects to improve state management and code maintainability.
Components previously handled dialog orchestration, installation validation, and subscription checks directly. This logic is now centralized within dedicated effects, making the components simpler and more focused on presentation.
Key changes:
- Installation, subscription, settings, and user management workflows are
now triggered by dispatching intent-based actions.
- Effects orchestrate the entire process, including validation chains and
opening necessary dialogs.
- The `SubscriptionDialogRouterService` has been removed as its logic is
now managed by effects.
- Plugin components (`-item`, `-detail`) are significantly simplified,
only dispatching actions.
Additionally, `PluginMetadataService.findOne` no longer throws an error on not found, returning null instead to allow for cleaner handling in effects.
* fix(plugins): stabilize plugin installation and subscription handling
This commit addresses several issues related to the reliability and UI feedback of plugin installation and subscription management in the marketplace.
- Use `concatMap` in effects to prevent race conditions during installation status checks, ensuring actions are processed in order.
- Improve the installation toggle UI by setting its state immediately when an installation starts and resetting it correctly if the user cancels the confirmation dialog.
- Add a new backend endpoint to fetch the current user's active subscription for a specific plugin, which is then consumed by the UI.
- Centralize subscription state logic by using the `accessFacade` and storing the full subscription object in the access store for consistent UI display.
- Correct a typo in the `getCurrentSubscription` API endpoint URL.
- After plugin activation, dispatch an action to re-check the installation status, ensuring the marketplace UI is up-to-date.
- Refactor the installation store's `setToggle` method for more robust state updates.
* refactor(plugins): move plugin action dispatching to effects
Centralize the dispatching of secondary actions for the plugin marketplace into the `getOne$` effect. This removes scattered logic from components and adheres more closely to state management best practices.
The `getOne$` effect now dispatches actions to check installation status, select the plugin version, and select the plugin source upon successfully fetching a plugin. This logic was previously handled within the `PluginMarketplaceItemComponent`.
Additionally, the `SettingsTabComponent` now dispatches an action to open the settings dialog instead of calling the dialog service directly, further decoupling the component from implementation details.
* refactor(plugins): simplify plugin installation status checking
Remove the manual installation check and UI toggle state management.
Previously, a dedicated action/effect (`checkInstallation`) and a
'toggles' array in the store were used to track whether a marketplace
plugin was installed. This approach was complex and could lead to state
synchronization issues.
This change introduces a more robust method by deriving the installation
status directly from the single source of truth: the list of locally
installed plugins. A new `installed$` query has been added for this
purpose.
Effects for installation, uninstallation, and failures now simply
dispatch a refresh action, ensuring the UI always reflects the correct
state reactively.
* feat(plugins): implement optimistic UI for installation toggle
Introduce a new state management slice for the plugin installation toggle to provide immediate visual feedback for user actions in the marketplace. This implements an optimistic UI pattern.
Previously, the UI would wait for the entire installation or uninstallation process to complete before updating the toggle's state, leading to a sluggish user experience.
This change introduces `PluginToggleStore` and related effects/actions:
- The toggle state now updates instantly when a user initiates an install or uninstall action.
- If the backend operation fails or is canceled, the toggle reverts to its previous state.
- On success, the toggle's new state is confirmed.
Additionally, this resolves a UI bug where loading spinners would activate on all plugin items simultaneously. Spinners are now correctly scoped to only the specific plugin being installed, updated, or uninstalled.
* fix(plugins): correctly sync plugin toggle state after installation
The plugin toggle in the marketplace detail view did not automatically
enable after a successful installation, nor did it consistently reflect
the plugin's true enabled state.
This was caused by two issues:
1. The `activationCompleted` effect was using an incorrect ID to dispatch
the toggle action. It now correctly uses `marketplaceId`.
2. The component's toggle state was not reactively driven by the actual
installation status.
This change ensures the toggle state is updated by subscribing to the
installation query, providing a reliable single source of truth for the UI.
* fix(plugins): revert plugin toggle state on uninstall failure
The plugin uninstall effect would immediately toggle the plugin to disabled
in the UI. If the uninstall operation failed, the toggle would remain
in the disabled state, which was inconsistent with the plugin's actual
installed state.
The uninstall handlers now return a boolean indicating success or failure.
The main effect uses this result to correctly set the toggle's state. If
the uninstall fails, the toggle is reverted back to its enabled state,
ensuring UI consistency.
* refactor(plugins): enhance installation state handling in marketplace components
* refactor(plugins): track operation states on a per-plugin basis
The previous state management for plugin operations used global flags for
states like `installing`, `updating`, and `deleting`. This led to a UI
bug where performing an action on a single plugin would incorrectly
display a loading state for all plugins in the marketplace.
This commit refactors the plugin state stores (installation, marketplace,
version, source) to manage these states in records keyed by the plugin
ID.
- State properties are changed from `boolean` to `Record<string, boolean>`.
- Stores, queries, and effects are updated to operate on specific plugin
IDs.
- UI components are modified to consume this new per-plugin state,
ensuring that loading indicators and disabled states are isolated to
the correct plugin item.
Additionally, the installation validation chain has been hardened with
more robust error handling and improved subscription management.
* fix(plugins): correctly handle installation flow after plan selection
The plugin installation process after the subscription plan selection
dialog was flawed. Canceling the dialog left the plugin toggle enabled,
and proceeding did not trigger the installation.
This commit adjusts the plan selection effect to correctly dispatch
actions based on the dialog's outcome:
- Revert the plugin toggle to 'off' if the user cancels.
- Trigger the plugin installation if the user proceeds.
Additionally, state queries for `installing$`, `uninstalling$`, and
`uploading$` are refactored. They can now check the global status (i.e.,
if *any* plugin is undergoing an operation), which simplifies disabling
UI controls during these processes.
* refactor(plugins): remove unused DataSource dependency and transaction handling in delete plugin command
* feat(plugin-marketplace): revert plugin toggle when subscription flow is cancelled
When a user toggles a plugin that requires a subscription, the
subscription management dialog is shown. If the user closes this dialog
without completing the process, the toggle previously remained in its
new, misleading state.
This change introduces logic to automatically revert the toggle state if
the subscription flow was initiated by the toggle action and then
cancelled. A `clicked` flag distinguishes between manual and automatic
dialog openings to ensure the toggle is only reverted in the latter case.
* feat(cdn-download): enhance plugin download strategy with streaming support and improved error handling
* fix(plugin-installation): add unique index for plugin installation fields
* feat(plugin): implement soft delete for plugins
Replace hard deletion with a soft delete mechanism. This change prevents permanent data loss and preserves plugin history for auditing or recovery purposes.
The `DeletePluginCommandHandler` now calls `pluginService.softDelete` and returns a success message with a status code upon completion.
BREAKING CHANGE: The `DeletePluginCommandHandler` now returns an object `{ message: string, status: number }` instead of `void`. Consumers of this command must be updated to handle the new return value.
* feat(plugins): open settings and user management dialogs via effects
Create NgNeat effects to handle the opening of plugin management dialogs.
The `openSettings$` effect in `PluginSettingsEffects` listens for the
`openSettings` action and opens the `PluginSettingsManagementComponent`.
Similarly, the `openUserManagementDialog$` effect in
`PluginUserAssignmentEffects` listens for the `manageUsers` action to
open the `PluginUserManagementComponent`.
This approach centralizes the dialog opening logic within the state
management layer.
* feat(i18n): add translations for plugin management and validation
Adds a comprehensive set of new English translation strings to support
upcoming enhancements to the plugin marketplace and management features.
This includes:
- A new `VALIDATION` section for various plugin lifecycle errors.
- More specific error messages for the "Assign Users" modal.
- A new "View Subscription" button label.
- Improved wording for plugin-related empty state messages for clarity.
* fix(registry): correctly load tenant relations for assignment check
The `determineAssignmentPermissions` method previously accepted a `pluginTenant` object, which could lead to incorrect permission calculations if the required user and role relations were not pre-loaded by the caller.
This change refactors the method to accept a `pluginTenantId` instead. It now explicitly fetches the `pluginTenant` entity with its `allowedUsers`, `deniedUsers`, and `allowedRoles` relations, ensuring that the permission logic always has the necessary data to operate correctly.
* refactor(plugins): decouple user assignments from plugin installations
This refactor removes the tight coupling between plugin user assignments
and the `PluginInstallation` entity. User assignments are now tracked
at a higher level, abstracting away the specific installation instance.
On the backend, a new `PluginTenant` entity is introduced to manage the
relationship between a plugin and a tenant/organization, serving as the
anchor for user assignments.
This change simplifies the overall data model and the public API for
managing user access to plugins.
Key changes include:
- Replaced `installationId` with `subscriptionId` or removed it
entirely from frontend state management and service calls.
- Renamed `pluginInstallationId` to `pluginSubscriptionId` in data models.
- Simplified API endpoints for fetching user assignments, e.g., from
`.../installations/:id/users` to `/plugins/:pluginId/users`.
- Updated backend command handlers to use the new `PluginTenant` service
for assignment and revocation logic.
BREAKING CHANGE: The API and frontend service layer for plugin user
assignments have changed. `installationId` is no longer used to scope
user assignments. Methods like `loadAssignmentsForInstallation` have been
removed, and signatures for many other methods in facades and services
have been updated.
* feat(plugins): implement plugin tenant based user management
This refactors the entire plugin user assignment system to use a new "Plugin Tenant" access control model, replacing the previous subscription-based logic. Plugin tenants now directly manage user access through explicit `allowedUsers` and `deniedUsers` lists.
Frontend Changes:
- New NgRx actions, effects, and facade methods are introduced for managing users within a plugin tenant context (e.g., `loadAllowedUsersForPlugin`, `allowUsersToPluginTenant`, `removeAllowedUsersFromPluginTenant`).
- The component logic is updated to first resolve a `pluginTenantId` for a given plugin and then perform user management operations against that tenant.
- State management is updated to store the `currentPluginTenantId`.
Backend Changes:
- New API endpoints are added to manage plugin tenant users (`POST /plugin-tenants/:id/users`) and to resolve a plugin tenant from a plugin ID (`GET /plugins/:id/tenant`).
- CQRS commands (`ManagePluginTenantUsersCommand`) and queries (`GetPluginTenantUsersQuery`) are implemented to handle the new ACL logic.
This provides a more robust and explicit mechanism for controlling user access to plugins.
BREAKING CHANGE: The plugin user assignment system has been completely overhauled. The previous subscription-based user access model is replaced by a new Plugin Tenant access control list (ACL) model. API endpoints and frontend state management for user assignment are not backward compatible.
* refactor(plugin): simplify subscription finding and access logic
Remove the complex Strategy and Registry patterns for locating plugin
subscriptions. The multiple finder classes and registry are replaced with a
single private `findSubscriptionByContext` method within the service.
This consolidation simplifies the architecture, reduces boilerplate, and
makes the subscription lookup process more direct and maintainable.
Additionally, this commit includes the following fixes:
- Allow access for subscriptions with `TRIAL` or `PENDING` statuses,
not just `ACTIVE`.
- Grant access by default when a plugin has no `PluginTenant`
configuration, treating it as a non-restricted plugin.
- Add null-safety checks in the access context factory to prevent
runtime errors.
* refactor(plugins): simplify user loading in user management
The logic for loading available users relied on subscribing to the
`selectedOrganization$` observable to get the current organization and
tenant IDs.
This approach was unnecessarily complex as these values are available
directly on the store. This commit refactors the component to access
`store.organizationId` and `store.tenantId` directly.
This removes the verbose observable pipeline, resulting in cleaner and
more straightforward code.
* feat(subscription): link plugin user access to child subscriptions
Automate the creation and revocation of user-specific (child)
subscriptions based on their access rights to a plugin. When an
administrator allows a user to access a plugin, a child subscription
is now automatically created, effectively assigning them a seat from
the parent (organization/tenant) subscription.
- The `ManagePluginTenantUsers` handler now orchestrates this process.
- `createChildSubscriptions` is called when users are allowed access.
- `revokeChildSubscriptions` is called when users are denied or removed.
- The logic to find the applicable parent subscription has been refined
to correctly identify tenant or organization-level subscriptions.
- The `createChildSubscriptions` service method is now more robust.
* fix(plugin-subscription): correct user subscription management and sharing checks
User-scoped subscriptions that are inherited from an organization or tenant
subscription should not be directly manageable by the end-user. This
commit adjusts the `canBeManagedByUser` method to only permit management
for non-inherited (top-level) user subscriptions.
Additionally, the `isSharableWithOrganization` static method is
corrected to check for `parentId` instead of the `parent` object,
ensuring accurate sharability evaluation.
* feat(plugin-marketplace): redesign current subscription card
Overhaul the UI for displaying the user's current plugin subscription.
The previous design was a simple list of details and lacked visual
clarity and impact.
This commit introduces a modern, card-based layout that better
organizes information and highlights critical statuses. The new design is
more engaging and makes it easier for users to understand their plan
at a glance.
Key improvements include:
- A prominent header with plan badges, title, description, and price.
- Status ribbons to clearly indicate "Trial" or "Expiring Soon" states.
- A grid of detail cards with icons for key dates (next billing, trial
end, etc.).
- Enhanced visual cues and animations for warning and danger states.
- Redesigned and more accessible action buttons.
- Improved responsive layout for tablet and mobile views.
* refactor(plugin-subscription): use RequestContext.currentUserId directly
Instead of fetching the entire `currentUser` object and then accessing its `employeeId` property, this change uses `RequestContext.currentUserId()` directly.
This simplifies the subscriber lookup logic within the cancellation handler and makes the code's intent clearer.
* feat(plugin-marketplace): trigger install/update/uninstall after subscription change
Previously, only new plugin subscriptions would trigger an automatic
installation. Changes to existing subscriptions, such as upgrades,
downgrades, or cancellations, required manual user intervention to
update or uninstall the corresponding plugin.
This change enhances the subscription flow by automating these actions:
- The subscription manager dialog now communicates the specific action
(e.g., 'subscribed', 'upgraded', 'cancelled') back to the effects.
- The subscription effect now triggers the appropriate marketplace
action: install for new subscriptions, update for plan changes, and
uninstall for cancellations.
- A new query is added to find the local installation ID from a
marketplace plugin ID, enabling targeted uninstalls.
* refactor(plugins): unify marketplace dialog widths and improve user management logic
Unify the width of the Subscription Manager, Plan Selection, and User
Management dialogs to a consistent 900px for a more cohesive UI.
Additionally, refactor the RxJS streams in the
PluginUserManagementComponent to avoid nested subscriptions and ensure
single emissions. The logic for assigning and unassigning users now
uses `take(1)` and `switchMap` for a more robust and declarative
observable chain.
* fix(plugins): improve subscription action logic and plan selection flow
Correct the behavior following a subscription change for a plugin that is
not yet installed. Previously, an 'update' action was always dispatched
for upgrades/downgrades, which would fail. Now, check for an existing
installation and dispatch 'install' if necessary. This also handles cases
where the user closes the subscription dialog without making a change.
Additionally, refactor the plan selection effect to resolve the plugin
before opening the dialog. This makes the flow more robust by handling
cases where the plugin might not exist and simplifies data passing.
* fix(plugin-marketplace): use relative path for back navigation
The `navigateBack` method was using an absolute path, which can be less reliable depending on the application's base URL configuration.
This commit updates the `router.navigate` call to use a relative path array, ensuring more robust and predictable navigation behavior.
* refactor(plugin-plan): Improve type safety in PluginPlanQuery
The `PluginPlanQuery` constructor and the `getValue()` method were casting `PluginPlanStore` to `any` or not explicitly typing the return of `getValue()`. This change removes the unnecessary `as any` cast in the constructor and ensures that the return type of `getValue()` is correctly inferred, improving type safety and maintainability.
* fix(installation-validation-chain): improve error handling and observable usage
Refactor the `validate` and `canProceedWithInstallation` methods to use RxJS operators (`catchError`, `defer`, `tap`, `map`, `of`) for more robust error handling and cleaner observable management.
Previously, explicit `Observable` creation was used, which could lead to unhandled errors and less idiomatic RxJS usage. This change ensures that errors during chain building are caught and reported within the context, and that observables are properly completed or returned. The `canProceedWithInstallation` method now directly pipes from `validate`, simplifying its logic and error handling.
* refactor(plugin-access): use of() for Observable creation
Replaced manual Observable creation with `of()` for cleaner and more concise Observable emission. This change simplifies the code in `PluginAccessGuard` and `PluginInstallationFacade` when dealing with immediate, non-async observable results.
* refactor(plugin-marketplace): rename PluginInstallationFacade to PluginInstallationContext
The `PluginInstallationFacade` was renamed to `PluginInstallationContext` to better reflect its role in managing the state and logic related to plugin installation.
This change involves renaming the class and updating its references within the `plugin-marketplace` services. The public API of the class has also been slightly adjusted to use more concise method names (`validate` instead of `validateInstallation`, and `prepare` instead of `prepareForInstallation`). These method name changes are not breaking as they are internal to the context.
The `SubscriptionValidator` has been updated to use the new context name and its methods.
* refactor(installation-validator): rewrite validation chain logic
Refactors the `InstallationValidator` abstract class to use RxJS operators for a more declarative and robust implementation of the validation chain.
This change improves error handling, simplifies subscription management, and makes the chain continuation more explicit. The core logic of individual validators remains unchanged, focusing on the orchestrator pattern.
The following changes were made:
- Replaced manual subscription management with `pipe`, `map`, `switchMap`, and `catchError`.
- Introduced private helper methods (`applyResult`, `proceed`, `fail`) to encapsulate logic.
- Updated type hint for `metadata` from `any` to `unknown`.
- Renamed `nextValidator` to `next` for brevity.
* fix(plugins): use concatMap for sequential subscription validation
Replaces `switchMap` with `concatMap` in the `SubscriptionValidator`. This ensures that subscription validation occurs sequentially, preventing potential race conditions and ensuring that the correct subscription status is evaluated before proceeding.
* fix(plugin-installation): streamline plugin installation flow
Refactor the plugin installation effect to better manage the user experience and error handling.
The changes include:
- Moving validation logic and dialog orchestration out of components into effects.
- Implementing an optimistic toggle enablement before validation.
- Introducing `exhaustMap` to prevent concurrent installations of the same plugin.
- Extracting dialog opening logic into a private helper method for better testability.
- Enhancing error handling to catch and gracefully manage issues during the validation or dialog process.
- Simplifying the validation chain to directly return a boolean indicating whether to proceed, rather than a detailed context object with errors.
- Making the `validate` method private, as its direct use is no longer intended outside the effect.
* refactor(plugins): shorten installation strategy method names
Renames `validateInstallation` to `validate` and `prepareForInstallation` to `prepare` on the `IPluginInstallationStrategy` interface and its implementations. This simplifies the method signatures and makes them more concise without altering their functionality.
* fix(plugins): open subscription dialog without blocking preparation
The `validateAndPrepare` method in `PluginInstallationContext` and the `prepare` method in `SubscriptionPluginInstallationStrategy` were updated to correctly handle the scenario where a subscription is required but missing.
Previously, the logic would attempt to prepare the subscription and then re-validate, which could lead to unexpected behavior or infinite loops if the subscription process itself was not immediate.
The changes now ensure that:
- If a subscription is required and missing, the subscription dialog is opened.
- The `prepare` method returns an observable that completes immediately after opening the dialog, allowing the `validateAndPrepare` method to return a result indicating that preparation is in progress but further action from the user is needed.
- The user is explicitly informed that they need to complete the subscription and retry the installation.
This provides a clearer user experience and prevents blocking the installation process unnecessarily while waiting for an asynchronous subscription action.
The `SubscriptionValidator` was also updated to reflect this change, returning `canProceed: false` after opening the subscription dialog, indicating that the user must subscribe and retry.
* refactor(plugin-subscription): Improve effect error handling and add success actions
This commit refactors the plugin subscription effects to provide more robust error handling and introduce explicit success actions for various operations.
The changes include:
- Catching errors and dispatching specific failure actions instead of returning `EMPTY`.
- Returning success actions after successful operations to allow for further side effects.
- Adjusting `createEffect` configurations to `dispatch: true` where appropriate to ensure actions are dispatched.
- Adding new effects to handle success and failure actions for create, update, cancel, upgrade, and downgrade subscriptions, as well as loading analytics.
- Introducing a new effect `openHierarchySubscriptions$` to handle opening the subscription dialog and loading relevant data.
- Modifying the `cancelSubscription$` effect to also update the current plugin subscription and selected subscription.
- Adding new UI-related effects that dispatch `false` to avoid unnecessary dispatches.
- Ensuring that refreshing the plugin list occurs after certain successful operations like creation, update, cancel, and upgrade.
- Setting loading states correctly in various success and failure handlers.
* fix(plugin-subscription): handle missing subscription plan data
Addresses potential issues when a subscription's plan data is missing or undefined. This prevents errors and ensures correct logic for comparing subscription plans, especially when a current subscription might not have a `plan` property or `plan.type`.
This change also refactors some internal comparisons to safely access `plan.type`, `plan.billingPeriod`, and `plan.price` using the nullish coalescing operator (`??`) or optional chaining (`?.`).
This ensures that the system can correctly determine if a user is selecting a new plan or sticking with their current one, even if the current subscription's plan details are incomplete.
* fix(plugin-subscription): remove public decorator from getCurrentSubscription
The `getCurrentSubscription` endpoint should not be publicly accessible. It requires authentication and authorization. This commit removes the `@Public()` decorator, ensuring that users must be authenticated to access their subscription information.
* fix(plugins): remove public decorator from subscription controller
The `@Public()` decorator was incorrectly applied to routes within the `PluginSubscriptionController`. This commit removes the decorator to enforce proper authentication and authorization for these endpoints, ensuring that only authenticated users with the necessary permissions can access plugin subscription information.
The `TenantPermissionGuard` and `PermissionGuard` are now explicitly applied at the controller level, which is the intended way to secure these routes.
* refactor(registry): extract subscription query logic
This commit refactors the `GetActivePluginSubscriptionQueryHandler` by extracting the logic for building query conditions, finding subscriptions, and validating them into separate private methods.
This improves code readability and maintainability by breaking down the complex `execute` method into smaller, more focused functions. It also makes the code easier to test and reuse.
* feat(plugin-registry): cascade cancellation to child subscriptions
When a parent plugin subscription is cancelled, all its active child subscriptions will now also be automatically cancelled. This ensures a consistent state across related subscriptions.
Child subscription cancellations will not affect parent or sibling subscriptions. New metadata is added to track cascaded cancellations.
* feat(plugin-subscription): cascade plan changes to child subscriptions
Introduce logic to cascade plan upgrades and downgrades from a parent subscription to its active child subscriptions. This ensures that child subscriptions automatically adopt the plan of their parent when the parent's plan changes.
Child subscriptions will have their `planId` updated to match the parent's new plan. Metadata will be added to both the parent and child subscriptions to track the cascade event, including the previous plan ID, the type of cascade (upgrade/downgrade), and which subscription initiated the change.
This change also adds checks to `canBeUpgraded`, `canBeDowngraded`, `canExtendTrial`, and `canCreateChildSubscriptions` to prevent these actions on child subscriptions, reinforcing that only parent subscriptions manage plan changes for their children.
* refactor(plugin-subscription): improve upgradeChildSubscriptions logic
The `upgradeChildSubscriptions` method was refactored to correctly identify and upgrade child subscriptions.
Previously, the logic incorrectly checked `parentSubscription.parentId` to determine if a subscription was a child, which is the opposite of its intended purpose. The check has been updated to use `subscription.isInheritedSubscription()` to accurately determine if the subscription is a parent and therefore has children to upgrade.
Additionally, the retrieval of active children was updated to directly use the result of `pluginSubscriptionService.find`, as it now returns an array directly, not wrapped in an `items` property. Parameter names were also clarified for better readability.
* feat(plugins): cascade renewals to child subscriptions
Implement the logic to automatically renew active child subscriptions when a parent subscription is renewed.
The `renew-plugin-subscription.handler.ts` now checks if the subscription being renewed is a parent subscription. If it is, it finds all active child subscriptions associated with it and renews them using the same calculated new end date. Metadata is added to both parent and child subscriptions to track this cascading renewal.
The `cancel-plugin-subscription.handler.ts` has also been updated to use a more accurate check for inherited subscriptions, ensuring that cancellation logic is applied correctly to child subscriptions.
* refactor(plugin-subscription): rename isInheritedSubscription to isInherited
Renames the `isInheritedSubscription` method and its related static method to `isInherited` for conciseness and clarity.
This change updates the method name used in several command handlers (`cancel-plugin-subscription`, `downgrade-plugin-subscription`, `renew-plugin-subscription`, `upgrade-plugin-subscription`) and the `SubscriptionAccessContextFactory` to reflect the new method name. The logic remains the same.
* fix(plugin-subscription): use isInherited for upgrade/downgrade checks
Replaces direct checks for `!this.parentId` with `!this.isInherited()` in the `canBeUpgraded`, `canBeDowngraded`, `isTrialExpired`, and `canCancel` methods. This change ensures that the logic correctly reflects whether a subscription is inherited, providing a more robust and maintainable condition for these operations.
* fix(plugin-subscription): correct condition for skipping inherited subscriptions
The logic for skipping child subscriptions in the `CancelPluginSubscription`, `DowngradePluginSubscription`, `RenewPluginSubscription`, and `UpgradePluginSubscription` handlers was inverted.
Previously, the handlers would skip execution if the `subscription.isInherited()` returned `false`. This commit corrects the condition to `subscription.isInherited()`, ensuring that the logic to skip child subscriptions is applied correctly. This means the handlers will now execute for non-inherited subscriptions and skip for inherited ones, as intended.
* refactor(plugins): improve plugin subscription and tenant management
This commit introduces several refactors and improvements to the plugin subscription and plugin tenant management modules.
Key changes include:
- **Plugin Subscription Handlers:**
- Modified `CancelPluginSubscriptionCommandHandler`, `DowngradePluginSubscriptionCommandHandler`, `RenewPluginSubscriptionCommandHandler`, and `UpgradePluginSubscriptionCommandHandler` to save cancelled/downgraded/renewed/upgraded children individually using `Promise.all` instead of a batch save. This addresses potential issues with the `pluginSubscriptionService.save` method not supporting array inputs.
- Added `relations: ['plan', 'plugin', 'pluginTenant']` to the `find` query in `cancel-plugin-subscription.handler.ts` to ensure all necessary related data is fetched.
- **Plugin Tenant Entity:**
- Refactored the `PluginTenant.create` method to apply all provided parameters first using `Object.assign`, and then apply default values using nullish coalescing (`??=`). This ensures that explicitly provided `null` values are respected.
- Reset `currentInstallations` and `currentActiveUsers` to 0 if not provided, ensuring a clean state for new instances.
- **Plugin Subscription Service:**
- Improved the `assignUsers` method:
- It now performs a single query to find existing child subscriptions, reducing the number of database calls.
- It filters out users who already have a subscription, creating new ones only for unassigned users.
- Child subscriptions are now created in parallel using `Promise.all`.
- Added logging for the number of child subscriptions created.
- Moved the `Logger` initialization to be a class property in `PluginSubscriptionService`.
- **Plugin Tenant Service:**
- Modified `findOrCreate` to accept and set the `scope` parameter, ensuring it's correctly applied when a new `PluginTenant` is created.
* fix(plugin-installation): improve uninstall flow error handling and dispatch
The uninstall flow in the plugin installation effects was not correctly handling errors or dispatching subsequent actions. This commit refactors the `uninstall$` effect to:
- Use `switchMap` and `of` to correctly emit multiple actions from the observable.
- Ensure that the `PluginActions.refresh()` action is dispatched even when the uninstall operation is successful or fails.
- Explicitly set `dispatch: false` for the `reset$` effect as it does not dispatch any actions.
* fix(plugin-installation): open subscription management when plugin cannot be installed
When a plugin installation is blocked because the user does not have the necessary subscription, the system should now open the subscription management modal. Previously, it would only display an informational message and disable the plugin toggle without offering a direct path to resolve the subscription issue.
This change ensures that users are immediately prompted to manage their subscriptions, streamlining the process of installing plugins that require them. The plugin toggle is still disabled to reflect the current installation state.
* fix(registry): improve error handling in get active plugin subscription
The previous implementation wrapped the subscription fetching logic in a try-catch block which would return null on any error. This commit refactors the `findSubscription` method to use `findOneOrFailByOptions` and explicitly check the `success` property. This allows for more granular error handling and avoids returning null for all potential issues during the fetch operation. It also removes the unnecessary try-catch block from the `execute` method.
* refactor(plugins): remove unused Actions import
The `Actions` import from `@ngneat/effects-ng` was not being used in the `SubscriptionPluginInstallationStrategy` class and can be safely removed. This is a cleanup operation that does not affect the functionality of the code.
* fix(plugin): refactor subscription access validation
Replaces the `PluginSubscriptionAccessFacade` with `PluginSubscriptionAccessService` in `SubscriptionPluginInstallationStrategy`.
Also updates `AccessValidator` to use `PluginSubscriptionAccessService` and adds error handling for subscription and access checks.
Introduces `NotFoundException` in `GetActivePluginSubscriptionQueryHandler` when no active subscription is found.
* fix(plugins): move toastr notification to success effect
The toastr notification for a cancelled subscription was previously displayed within the `cancelSubscription` effect's `switchMap`. This has been moved to a new `tap` operator within the `cancelSubscriptionSuccess` effect.
This change ensures that the success message is only shown after the subscription has been successfully cancelled and the store has been updated. Additionally, the `concatMap` operator is now used instead of `switchMap` in the `cancelSubscription` effect to ensure that consecutive cancel subscription requests are processed in order.
The caching logic related to subscriptions and plans has also been removed from the `PluginSubscriptionService` as it was no longer being utilized.
* refactor(plugin-subscription): remove showSubscriptionDialog handling and related actions
* fix(plugin-subscription-manager): improve null safety and subscription handling
Add optional chaining to `currentSubscription?.parentId` in the template to prevent potential errors if `currentSubscription` is null.
Also, remove redundant `currentSubscription.plan.type` access in the component by utilizing the nullable access `this.currentSubscription.plan?.type`. This improves robustness when dealing with subscriptions that might not have a plan defined.
Finally, add `untilDestroyed(this)` to the `currentPlan$` subscription to ensure proper cleanup.
* feat(plugin-subscription-manager): improve subscription flow and UX
Refactors the plugin subscription manager component to improve user experience and streamline the subscription workflow.
Key changes include:
- Introduces a `currentSubscription$` observable for reactive handling of subscription state.
- Enhances the `setupCurrentPlan` method to correctly derive the current plan from both available plans and the user's subscription.
- Improves the `onPlanSelected` method to provide better feedback and handle plan changes more gracefully.
- Updates confirmation messages for cancellation, upgrade, and downgrade actions to be more informative and user-friendly, including prorated charges and end dates.
- Refines error handling and loading state management for subscription operations (create, cancel, update).
- Optimizes observable subscriptions using `shareReplay` and `pairwise` for better performance and clarity.
- Adds a `currentResolvedPlan` property to track the current plan in cases where `currentSubscription.plan` might not be immediately available.
- Improves the `canUpgrade` and `canDowngrade` logic to consider both `currentSubscription.plan` and the locally resolved `currentResolvedPlan`.
* docs: add persona instructions for angular and nebular
This commit adds new instruction files for the persona of an Angular developer and a Nebular architect. These files define the expected behavior, best practices, and output formats for each persona when generating code or UI.
* fix(contracts): update plugin subscription interfaces and enums
The `IPluginSubscription` interface has been significantly expanded to include more detailed fields related to subscription management, such as `planId`, `plan`, `scope`, `subscriberId`, `subscriber`, `startDate`, `endDate`, `trialEndDate`, `autoRenew`, `parentId`, `pluginTenantId`, `plugin`, `externalSubscriptionId`, `cancelledAt`, `cancellationReason`, and `metadata`.
New interfaces have been introduced:
- `IPluginSubscriptionPlan`: Replaces the previous `IPluginSubscriptionPlan` and includes fields like `scope`, `price`, `currency`, `billingPeriod`, `features`, `limitations`, `isPopular`, `isRecommended`, `trialDays`, `setupFee`, `discountPercentage`, `isActive`, `sortOrder`, and `metadata`.
- `IPluginBilling`: Defines the structure for plugin billing records.
- `IPluginPayment`: Defines the structure for plugin payment records.
- `IPluginSubscriptionCreateInput`: For creating new plugin subscriptions.
- `IPluginSubscriptionUpdateInput`: For updating existing plugin subscriptions.
- `IPluginPlanCreateInput`: For creating new plugin subscription plans.
Several enums have been added or refined:
- `PluginSubscriptionType`: Includes `FREE`, `TRIAL`, `BASIC`, `PREMIUM`, `ENTERPRISE`, `CUSTOM`.
- `PluginBillingPeriod`: Includes `DAILY`, `WEEKLY`, `MONTHLY`, `QUARTERLY`, `YEARLY`, `ONE_TIME`.
- `PluginSubscriptionStatus`: Includes `ACTIVE`, `CANCELLED`, `EXPIRED`, `TRIAL`, `PAST_DUE`, `SUSPENDED`, `PENDING`.
- `BillingStatus`: Includes `PENDING`, `PAID`, `FAILED`, `CANCELLED`, `REFUNDED`.
- `PaymentStatus`: Includes `PENDING`, `COMPLETED`, `FAILED`, `CANCELLED`, `REFUNDED`.
- `PaymentMethod`: Includes `CREDIT_CARD`, `DEBIT_CARD`, `PAYPAL`, `STRIPE`, `BANK_TRANSFER`, `CRYPTOCURRENCY`.
The changes in `packages/contracts` necessitate corresponding updates in the UI libraries to align with the new contract definitions. This commit ensures that the contracts accurately reflect the plugin subscription model.
* feat(instructions): enhance UI guidelines with dynamic border-radius and border usage
* fix(instructions): update persona description to reflect modern design principles
* feat(instructions): add box shadow guidelines for elevated elements
* feat(plugins): refactor subscription manager UI and UX
Refactors the plugin subscription manager UI and UX for a more intuitive and visually appealing experience.
Key changes include:
- **Component Restructuring:** Migrated elements to `nb-card` components for better structure and theming consistency.
- **Visual Enhancements:** Updated styles for headers, footers, and content sections to align with the Gauzy design system, including new card styles, shadows, and rounded corners.
- **Improved Readability:** Enhanced typography, spacing, and element grouping for better readability and scannability.
- **Interactive Elements:** Refined hover effects, animations, and button states for a more responsive feel.
- **Accessibility Improvements:** Added ARIA attributes for better screen reader support and clarified focus states.
- **State Management Refinements:** Adjusted component logic for smoother handling of loading, error, and empty states.
- **Theming Integration:** Ensured consistent use of Gauzy theme variables for colors, borders, and shadows.
- **Content Clarity:** Updated descriptive text and labels for better user understanding of subscription details and actions.
- **Feature Highlighting:** Enhanced the visibility of plan features and limitations.
- **Error Handling:** Improved the presentation of form validation and error messages.
* feat(ui-lib): refactor subscription preview card for clarity and structure
This commit refactors the HTML and SCSS for the subscription preview card in the plugin marketplace. The primary goals are to improve the clarity of the displayed information, enhance the visual structure, and make the component more maintainable.
Key changes include:
- Restructuring the HTML into semantic sections for "Price Breakdown", "Total", "Included Features", and "Footer".
- Updating CSS class names to be more descriptive (e.g., `order-summary-card`, `summary-header`, `price-label`).
- Enhancing accessibility with more specific ARIA attributes.
- Improving the visual styling for different sections, including dedicated styling for discount rows and free plans.
- Adding a "Secure & encrypted checkout" footer for user reassurance.
- Implementing responsive adjustments for smaller screens to ensure better usability.
* fix(plugin-marketplace): Refactor UI for plugin details and upload flows
This commit introduces significant UI improvements across several components related to the plugin marketplace, focusing on modernizing the look and feel, enhancing user experience, and improving usability.
Key changes include:
- **Plugin Details & Item Components:**
- Updated card styles for `plugin-card` and `plugin-details-card` with new color schemes, shadows, and border-radius for a cleaner, more contemporary appearance.
- Implemented smoother transitions and hover effects for better interactivity.
- Introduced new badges and styling for status, subscription, and security indicators to provide clearer visual feedback.
- Refactored the header section of `plugin-details-card` for better layout and information hierarchy.
- Enhanced plugin description, categories, tags, and metrics sections with improved styling for better readability.
- Updated action buttons for consistency and visual appeal.
- Improved the installation wrapper styles for free and subscription-required plugins.
- Introduced modern design elements for `dialog-create-source`, `dialog-create-version`, and `dialog-installation-validation` components, including updated headers, icons, and button styles.
- Lazy loading for plugin information tabs (`overview-tab`, `settings-tab`, `source-code-tab`, `user-management-tab`) is now more robustly styled.
- Revamped the layout and styling of the overview tab for better clarity of plugin information and usage statistics.
- Refined the settings tab UI with clear sections for configuration and feature highlights.
- Enhanced the source code tab with improved styling for file uploads and security information.
- Modernized the user management tab with clearer user assignment flows and improved display of user information.
- Updated version history component styling for better visual hierarchy and easier navigation.
- **Plugin Marketplace Filter:**
- Restyled the `marketplace-filter` component with a new color palette, shadows, and border-radius for consistency.
- Improved the filter header design with a new icon container and updated titles.
- Enhanced filter sections with better spacing, borders, and hover effects for headers.
- Introduced new animations (`pulse-badge`, `slide-down`, etc.) for a more dynamic user experience.
- Refined the styling for category items, checkboxes, and price ranges.
- Updated loading and empty states for better visual feedback.
- **Plugin Upload Components:**
- Redesigned the `file-upload` component with a modern look, including drag-and-drop visual feedback, file info display, and error handling.
- Introduced new headers and improved layouts for `plugin-basic-information`, `plugin-metadata`, `plugin-version`, `cdn-form`, `gauzy-form`, `npm-form`, and `plugin-source` components.
- Refined form field styles across all upload-related components for better consistency and user feedback (e.g., success states, validation hints).
- Updated subscription plan creator UI with a cleaner layout and improved input controls.
- Enhanced user assignment and revocation dialogs with updated headers, icons, and better visual hierarchy.
- Improved the overall layout and styling of the `plugin-marketplace-upload` component.
- **Plugin Marketplace Component:**
- Restyled the main `marketplace-container` with updated grid layouts, padding, and shadows.
- Modernized the results header with new icons, statistics display, and improved layout for view toggle and filter buttons.
- Updated the floating upload button (`upload-fab`) with improved styling, animations, and progress indicator.
- Refined the skeleton loader styles for a more visually appealing loading state.
* feat(plugin-marketplace): refactor manage plugin actions into popover
This commit refactors the "Owner" actions for a plugin in the marketplace to be presented within a popover. This improves the UI by decluttering the main plugin card and providing a more organized way to manage actions like adding versions, adding sources, editing, and deleting.
The changes include:
- Moving the "Add Version", "Add More Sources", "Edit", and "Delete" buttons into a new `nb-popover` element.
- Creating a new `ng-template` named `ownerActionsTemplate` to define the content of the popover.
- Updating the styling to accommodate the popover structure.
- Importing `NbPopoverModule` into `plugins.module.ts`.
- Adjusting the `results-header` styling in `plugin-marketplace.component.scss` for better responsiveness.
* refactor(plugin-upload): replace nb-form-field with div for consistency
Replaces `nb-form-field` with `div` elements in several template files related to plugin upload. This change aims to improve consistency in the markup structure for form groups within the plugin upload components.
This change does not alter the functionality or appearance of the components, only the underlying HTML structure.
* fix(ui): standardize nb-hint status usage to class-based styling
This commit refactors the usage of `nb-hint` components across various plugin upload forms. Previously, the `status` attribute was used directly, which is being deprecated or replaced by class-based styling in the UI library.
The changes involve:
- Replacing `status="danger"` with `class="hint-danger"`.
- Replacing `status="success"` with `class="hint-success"`.
- Replacing `status="info"` with `class="hint-info"`.
- Replacing `status="basic"` with `class="hint-basic"`.
This ensures consistent styling and leverages the intended mechanism for controlling hint appearance, improving maintainability and adhering to updated UI library practices. The corresponding SCSS files have also been updated to define these new classes for proper styling.
* fix(plugin-marketplace): improve styling and component structure
Refactor the plugin marketplace component to improve its styling and structure. This includes:
- Standardizing spacing with `rem` units.
- Restructuring the "Assign Users" button to be within the owner actions popover.
- Applying consistent styling to owner action buttons for a better user experience.
- Adjusting styles for badges and buttons within the marketplace components.
* fix(ui): ensure full width for code block links
Add `width: 100%;` to the `.value.code-block` and `.link` elements within the source code tab. This ensures that the code blocks and links within them occupy the full available width, improving usability and visual consistency.
* fix(plugin-marketplace): allow plugin marketplace dialog to expand
This change removes the `max-height` constraint from the plugin marketplace dialog's card element. This ensures that the dialog can properly display all plugin information without being cut off, especially for plugins with extensive descriptions or multiple items.
* feat(i18n): update plugin related translations
Introduce new keys and refine existing ones for better clarity and coverage in plugin-related internationalization strings.
This commit adds new sections for "Version Information" and enhances the existing "Toastr" messages to be more specific and informative. It also updates several "Info" and "Error" messages within the "Toastr" section to improve user feedback during plugin management operations. Additionally, new button labels and subscription-related text have been added to support expanded plugin functionalities.
* feat(plugin-marketplace): update scss and i18n for plugin details
- Refactor the styling for various plugin marketplace components to ensure consistent layout and responsiveness.
- Update the English translation file (`en.json`) with new keys and descriptions related to plugin details, configuration, and upload information.
- This change improves the user experience by providing clearer information and better visual presentation of plugin settings and upload forms.
* fix(plugin-marketplace): change add version icon
Update the icon used for the "Add Version" button in the plugin marketplace item component. The icon has been changed from "plus-outline" to "layers-outline" to better represent adding a new version of a plugin.
* fix(plugin-marketplace): ensure tab link border-radius is applied
The `border-radius` for the plugin marketplace tab links was not being applied correctly due to CSS specificity issues. This change adds an `!important` flag to the `border-radius` property to ensure it is consistently applied.
* fix(plugin-marketplace): rename viewSubscriptionHierarchy to viewSubscription
The method `viewSubscriptionHierarchy` was renamed to `viewSubscription` to better reflect its functionality, which is to view subscription details rather than a hierarchy. This change aligns with the action dispatched by the method, `PluginSubscriptionActions.openSubscriptionManagement`.
Additionally, the "Assign Users" button has been updated to use the `fullWidth` property and a new class `action-button` for consistent styling and to ensure it takes up the full width when needed.
* feat(plugin-marketplace): add loading indicator for subscription button
Introduces a loading spinner to the "View Subscription" button in the plugin marketplace item component. This provides visual feedback to the user while subscription details are being fetched, improving the user experience.
Additionally, the styling for the subscription button has been adjusted to ensure consistent border-radius behavior across different browser views, preventing visual glitches.
* fix(plugin-marketplace): handle missing plugin and show spinner on loading
Add a fallback to `this.pluginMarketplaceQuery.plugin` when looking up a plugin by ID in the `plugin-plan.effect.ts`. This ensures that if the plugin is not found in the `plugins` array, but is available as the currently selected `plugin`, it will be correctly retrieved.
Additionally, the spinner in the `plugin-marketplace-item.component.html` will now display when the subscription is loading, providing better user feedback during subscription state changes. The CSS for action buttons has been slightly adjusted for consistency.
* fix(ui): adjust plugin marketplace styling and icon
- Update plugin marketplace item to use 'more-vertical-outline' icon.
- Remove redundant background and border-radius from plugin-details-card.
- Add border-radius to the first child of nb-card-body in source-code-tab.
- Add 'plugin-list' class to plugin-marketplace component's scrollable content.
- Apply border-radius to the 'plugin-list' class for consistent styling.
* fix(plugin-marketplace): position badges absolutely
Adds `position: absolute !important` to `nb-badge` elements within the plugin marketplace filter and user management components. This ensures that badges are correctly positioned relative to their parent elements, preventing layout issues and improving visual consistency.
* refactor(desktop-ui-lib): update plugin user management styles
Refactor the SCSS styles for the plugin user management component to improve readability and maintainability. This includes adjusting spacing, borders, and using more consistent naming conventions for CSS classes. The overall visual appearance should remain largely the same, but the underlying structure of the styles is enhanced.
* feat(plugin-user-management): improve user assignment display
Add a new derived state variable `isAssignedAvailable` to conditionally display the assigned user count badge. This improves the UI by only showing the assignment count when there are actually users assigned, making the interface cleaner when no users are yet assigned.
Also, add comments to the template for better readability.
* fix(plugin-marketplace): unify status attribute quotes and center button alignment
* refactor(styles): consolidate common scss styles
This commit refactors several SCSS files within the plugin marketplace upload components by consolidating and standardizing common styling rules.
The changes include:
- Standardizing the structure and styling of headers across different plugin upload sections (basic info, metadata, CDN, npm, version).
- Consolidating styles for form fields, hints, and alerts to ensure consistency.
- Adjusting responsive styles for better uniformity across various screen sizes.
- Keeping the animation for form validation feedback consistent.
These changes aim to improve maintainability and ensure a cohesive user interface across the plugin upload process.
* feat(plugin-settings): add create and delete setting functionalities
- Implemented `onDeleteSetting` method in `PluginSettingsManagementComponent` to handle setting deletion with confirmation.
- Added `onCreateSetting` method to open a dialog for creating new settings.
- Created `PluginCreateSettingDialogComponent` for the creation form with a reactive form setup.
- Added styles and HTML structure for the create setting dialog.
- Updated `PluginSettingController` to include a new endpoint for deleting plugin settings.
- Enhanced the plugin settings management with new actions and state management for creating settings.
* fix(instructions): update applyTo patterns to include component file extensions
* feat(plugins): implement plugin category management
This commit introduces comprehensive management capabilities for plugin categories, enabling users to create, select, and organize plugins by categories.
Key changes include:
- **`IPluginCategory` Interface Enhancements**: The `IPluginCategory` interface in `@gauzy/contracts` has been extended with properties like `slug`, `color`, `order`, `parentId`, and `parent`, providing richer metadata for categories.
- **`CategorySelectorComponent`**: A new Angular component (`@desktop-ui-lib`) has been developed to allow users to select a plugin category from a dropdown list. This component supports infinite scrolling for loading categories and a feature to create new categories on the fly.
- **`CreateCategoryDialogComponent`**: This component facilitates the creation of new plugin categories through a modal dialog. It includes fields for name, description, slug, order, color, and icon, with built-in presets for colors and icons.
- **Integration with Plugin Upload Form**: The `PluginBasicInformationComponent` now incorporates the `CategorySelectorComponent`, allowing users to assign a category to a plugin during the upload process. The `categoryId` is now a field in the plugin upload form.
- **Backend Updates**:
- **Plugin Category Service**: Enhancements were made to the `CreatePluginCategoryHandler` in `@plugins/registry` to validate slug uniqueness and parent category existence more robustly. The service now uses `findOneOrFailByWhereOptions` and `findOneOrFailByIdString` for clearer error handling.
- **Plugin Category Controller**: The `PluginCategoryController` in `@plugins/registry` has been updated to use the `CreatePluginCategoryDTO` and ensure default values for `order`.
- **Localization**: Added a new translation key for "Category" in `en.json`.
This feature significantly improves the organization and discoverability of plugins within the application.
* fix(plugin-marketplace): remove unused PluginSubscriptionService import
The `PluginSubscriptionService` was imported in `plugin-marketplace-upload.component.ts` but was not being used. This commit removes the unused import.
Additionally, a new field `categoryId` was added to the plugin data in `form-data.builder.ts`. This change appears to be related to the subscription service and might be a preparation for future functionality.
* fix(plugin-basic-information): sync category form control with query selection
Refactor the category synchronization logic to use `distinctUntilChanged` and ensure the form control value is only updated when it differs from the new selection. This prevents unnecessary updates and potential infinite loops.
The previous implementation would always set the form control value, even if it was already the same as the selected category, leading to redundant operations.
This change also removes the logic for setting the initial category when editing, as this is now handled by the general synchronization mechanism.
* refactor(plugin-basic-information): remove unused Actions import
The `Actions` import from `@ngneat/effects-ng` was no longer being used in the `PluginBasicInformationComponent`. This commit removes the unused import to clean up the code.
* feat(registry): add categoryId to plugin model and update command
Adds the `categoryId` field to the `IPlugin` model and allows it to be updated via the `UpdatePluginCommand`. This enables associating plugins with specific categories.
* fix(plugin-basic-information): prevent resetting category when category is already set
The filter condition was incorrectly excluding cases where the categoryControl.value was already set. This change ensures that the category is only reset if the new categoryId is different from the current categoryControl.value, preventing unnecessary updates when the category hasn't actually changed.
* feat(plugin-marketplace): add inline category creation
This commit introduces the ability to create a new plugin category directly from the category selector component, rather than navigating to a separate page.
The changes include:
- Adding a new action `createCategoryInline` to the `PluginCategoryActions`.
- Implementing an effect `createInline$` in `PluginCategoryEffects` that opens the `CreateCategoryDialogComponent` when the `createCategoryInline` action is dispatched.
- Modifying the `CategorySelectorComponent` to dispatch `createCategoryInline` when a new category name is provided.
- Updating the `CreateCategoryDialogComponent` to handle the inline creation flow and dispatch the appropriate actions upon successful creation.
- Adjusting `PluginBasicInformationComponent` to correctly bind the `categoryId` from the form to the `CategorySelectorComponent` and to properly sync category selection with the form.
* feat(marketplace): fetch plugin category
Include the 'category' relation when fetching plugin data in both the
PluginMarketplaceItemComponent and PluginMarketplaceComponent. This change
enables the display and filtering of plugins by their category in the
marketplace UI.
* feat(plugins): integrate category selector component
Replaces the input field for category with a dedicated category selector component in both the plugin creation dialog and the plugin settings management view. This provides a more user-friendly and consistent experience for managing plugin categories.
The form controls have been updated from `category` to `categoryId` to reflect the new component's input. The `CategorySelectorComponent` is now integrated and wired up to sync its selected value with the respective form groups.
* feat(plugin-marketplace): display plugin category
Add the display of plugin category information within the plugin marketplace item component. This includes showing the category icon and name, with styling to match the theme.
The layout for the header section in the plugin marketplace item has been adjusted to accommodate the new category display. The alignment of the header content has been changed from `center` to `flex-start` to better position the name and category information.
Styling has been introduced for the new category container to ensure consistent presentation with the rest of the UI. This includes defining display properties, font sizes, and weights.
* feat(plugin-settings): implement plugin setting edit mode and UI enhancements
This commit introduces a new edit mode for plugin settings, allowing users to modify individual settings directly within the UI. Key improvements include:
- **Edit Mode Management:** Actions and effects have been added to handle starting, updating, saving, and canceling edits for individual settings. This includes tracking dirty states and managing UI feedback.
- **UI Enhancements:**
- Refactored the `PluginSettingsManagementComponent` for a more modern and organized layout.
- Introduced inline editing for settings, with visual cues for editing and unsaved changes.
- Implemented `cdk-virtual-scroll-viewport` for improved performance when rendering large lists of settings.
- Added loading and empty states for a better user experience.
- Enhanced the search and filter controls with a dedicated section.
- Improved the display of setting values in view mode, with an edit icon to trigger editing.
- Added toasts for various setting operations (creation, update, deletion, validation, export, import).
- Updated the `deleteSetting` action in `plugin-settings.actions.ts` to include `pluginId`.
- **Backend Integration:**
- Updated the `PluginSettingsService` to remove caching logic, relying on Akita for state management.
- Modified the `deleteSetting` API endpoint to accept `pluginId` and `settingId`.
- Added a `settingsGroups$` observable to `PluginSettingsQuery` to store flattened settings for filtering.
- **Validation Improvements:**
- The `validateSettingsSchema` effect now handles array format for settings and converts it to a record if necessary.
- Added toast notifications for validation success and failure.
- **Code Refactoring:**
- Adopted `inject()` for dependency injection in components and services where appropriate, following Angular 20+ best practices.
- Updated `plugin-setting.service.ts` to include category sorting in `findAll` queries.
- Adjusted the `GetPluginSettingsByPluginIdQuery` in `plugin-setting.controller.ts` to include `organizationId` in the query.
* fix(plugin-settings): handle empty settings updates and set pluginId
Introduces a check in `PluginSettingsManagementComponent` to prevent making an API call for bulk plugin settings updates if there are no actual settings to update. This avoids unnecessary network requests.
Additionally, the `pluginId` is now correctly passed within the bulk update request object. This was previously missing and has been added to the `UpdatePluginSettingRequest` interface and the service DTO to ensure proper identification of the plugin being updated. This change also refactors the `BulkUpdatePluginSettingsRequest` interface to include an optional `pluginId`.
* feat(plugin-settings): add edit forms for individual plugin settings
Introduces editable forms for individual plugin settings, allowing users to modify settings in place without reloading the entire section. This includes managing the state of these edit forms and their values.
Also includes SCSS and HTML changes to visually accommodate the new editing functionality.
* feat(plugin-settings): enhance loading state with skeleton UI and improve layout styles
* feat(plugin-create-setting-dialog): improve input and select field styling
Enhance the styling of input and select fields within the plugin creation dialog for better visual consistency and user experience.
Key changes include:
- Applying `fieldSize="medium"` to various input and select elements for consistent sizing.
- Adding focus styles to input and select components for better visual feedback.
- Adjusting padding and spacing within the dialog to improve layout and readability.
- Implementing custom scrollbar styles for the dialog body for better usability with long content.
- Refined color palettes and typography to align with the overall application theme.
- Added `nbSpinner` to the submit button to indicate submission status.
* fix(plugin-settings): avoid unnecessary Set copying
The `startEditSetting`, `saveSettingEdit`, `completeSavingSettingEdit`, and `cancelSettingEdit` methods were creating new `Set` objects from existing `Set` objects unnecessarily. This commit removes the redundant `new Set()` calls, improving performance and simplifying the code.
* style(plugin-user-assignment-dialog): enhance SCSS structure and improve styling consistency
* fix(plugin-settings): remove unused pluginId from createSetting action
The `pluginId` parameter was being passed to the `createSetting` action but was not being used by the `pluginSettingsService.createSetting` method or the effect itself. This change removes the unused parameter to improve code clarity and maintainability.
* fix(plugin-settings): update settings groups on create/delete
Ensure that the `settingsGroups` state is correctly updated when a setting is created or deleted. This synchronizes the `filteredGroups$` observable with the latest changes, reflecting the addition of new settings or the removal of deleted ones, and also cleans up empty groups.
* fix(plugin-settings): adjust width of plugin settings management component
The width of the plugin settings management component was previously set to a fixed 1000px, which could lead to overflow issues on smaller screens. This change adjusts the width to be a responsive 60vw, ensuring better display across various screen sizes.
* fix(plan-card): adjust card layout and styles
This commit addresses several styling adjustments to the plan card component.
It includes:
- Added `max-height: fit-content` to ensure cards adjust their height appropriately.
- Minor adjustments to line heights and font sizes for better readability.
- Refined spacing and borders for a cleaner visual presentation.
- Ensured consistency in the application of various styles for different plan states (selected, current, disabled, popular, recommended, free).
* fix(plugin-user-management): add gap to card footer
Adds a gap of 1rem to the nb-card-footer within the plugin user management component. This aligns the buttons or other elements in the footer, improving the visual presentation and user experience.
* fix(plugin-marketplace): restrict settings and manage users to owner
Conditionally display the "Settings" and "Manage Users" options in the plugin marketplace detail view. These actions should only be available when the current user is the owner of the plugin.
This change ensures that sensitive management actions are not exposed to unauthorized users, improving security and user experience. Previously, these options might have been visible to non-owners depending on the plugin's installation status.
* refactor(registry): update user context and remove public decorators
This commit updates the `RequestContext` usage from `currentEmployeeId` to `currentUserId` in several query handlers within the registry plugin. This change ensures that the correct user context is being used for ownership validation.
Additionally, the `@Public()` decorator has been removed from the `findAll` methods in `PluginCategoryController`, `PluginSourceController`, and `PluginVersionController`. This implies a change in access control requirements, likely making these endpoints protected and requiring authentication.
* fix(plugins): use patch for restore version endpoint
The `restoreVersion` method in `PluginService` was incorrectly using a POST request to update the status of a plugin version. This commit changes the HTTP method to PATCH and sends the `status` in the request body, which aligns with RESTful API best practices for partial updates.
Additionally, styles were added to `version-history.component.scss` to ensure that `nb-badge` elements are rendered correctly within the plugin marketplace version history.
* feat: add plugin registry tables and entities
Adds database migrations and corresponding TypeORM entities for the plugin registry. This includes tables for:
- Plugins
- Plugin categories
- Plugin tags
- Plugin installations
- Plugin versions
- Plugin sources
- Plugin tenants
- Plugin settings
- Plugin subscription plans
- Plugin subscriptions
- Plugin billings
The migration also includes necessary indexes and foreign key constraints to maintain data integrity and optimize query performance. The schema definitions are designed to be compatible with PostgreSQL, MySQL, and SQLite databases.
This change lays the foundation for the plugin marketplace functionality, allowing for the management and discovery of plugins.
* fix(desktop-ui-lib): adjust plugin marketplace styles for better responsiveness
Refactors the CSS for the plugin marketplace component to improve responsiveness and address layout issues across different screen sizes.
Key changes include:
- Adjusting `max-height` for the `filter-panel` to ensure it fits within the viewport.
- Refining the `grid-view` styles in `content-active` for better column adaptation.
- Updating the `no-data` height to be responsive.
- Ensuring `ngx-no-data-message` takes up full width.
- Addressing `max-height` on `plugin-list` within `::ng-deep`.
* fix(migrations): add IF NOT EXISTS to unique index creation
Adds `IF NOT EXISTS` to the `CREATE UNIQUE INDEX` statements for `version_number_unique` and `plugin_name_unique`. This prevents errors if the migration is run multiple times or if the indexes already exist.
This change also includes a `try...catch` block around the `DROP INDEX` for `version_number_unique` in the `down` method to handle cases where the index might not exist.
* fix: correct data type for appliedAt in plugin_tags table
The `appliedAt` column in the `plugin_tags` table was incorrectly defined as `timestamp` and should be `text`. This change corrects the data type to ensure proper storage of applied date information. Additionally, the error handling for dropping the `version_number_unique` index on `plugin_versions` has been removed, as it's expected to exist during this migration.
* fix(registry): improve plugin creation and subscription plan handling
This commit addresses several issues related to plugin creation and subscription plan management within the registry module.
Key changes include:
- **Plugin Creation Validation:** Added more robust validation for plugin data during creation, specifically checking for the presence of version information.
- **Subscription Plan Handling:**
- Ensured that the `pluginId` is explicitly passed and validated when creating subscription plans.
- Marked `pluginId` as optional in `CreatePluginSubscriptionPlanDTO` to allow for cases where it's not immediately available, but added validation in the handler to ensure it's provided before creation.
- Adjusted `UpdatePluginDTO` to correctly handle both updates and creation of subscription plans, allowing for `CreatePluginSubscriptionPlanDTO` within the `subscriptionPlans` array.
- Made `isActive` optional in `CreatePluginSubscriptionPlanDTO` to align with default behavior.
These changes enhance the reliability and flexibility of the plugin and subscription plan creation process.
* fix(registry): update plugin tenant scope if provided
When a plugin tenant already exists and a new scope is provided during an update or creation attempt, the existing scope should be updated. Previously, if a plugin tenant existed, its scope was not modified even if a new scope was passed. This change ensures that the scope is updated if a new one is provided.
* fix(registry): update plugin tenant scope only if changed
Avoids unnecessary database writes when the plugin tenant scope is the same.
This change ensures that the `save` method is only called if the provided `scope`
is different from the `existingPluginTenant.scope`, preventing redundant database
operations.
* feat(plugins): introduce subscription billing form components
This commit introduces a new set of components for the subscription billing form, enhancing the plugin marketplace user experience. The changes include:
- **Billing Cycle Section:** Allows users to select their preferred billing period (monthly, quarterly, yearly) with clear pricing and descriptions.
- **Payment Method Section:** Enables users to choose between credit/debit card and PayPal, displaying relevant details and security assurances.
- **Card Details Section:** Collects necessary credit card information for secure processing, including card number, expiry date, and CVV, with appropriate validation.
- **Billing Contact Section:** Gathers the user's full name and email address for billing purposes, ensuring accurate communication.
- **Subscription Consent Section:** Includes options for enabling automatic renewal and accepting terms of service and privacy policy, crucial for subscription agreements.
- **Refactored Plugin Subscription Manager:** The existing `plugin-subscription-manager.component.html` has been updated to integrate the new billing components, and the price period display logic has been improved.
- **Modularization:** The new components are designed to be reusable and are exported from the shared module.
This refactoring aims to provide a more organized, user-friendly, and robust billing process for plugin subscriptions.
* fix(payment-method-section): refactor to use buttons for payment method selection
This commit refactors the payment method selection in the subscription billing form. Previously, radio buttons were used, which had some accessibility and styling limitations.
The changes include:
- Replacing `nb-radio-group` and `nb-radio` with a `div` acting as a radiogroup and `button` elements for each payment method.
- This allows for better control over styling and interaction, including hover effects, selected states, and a visual selection indicator.
- Improved accessibility by using `role="radiogroup"`, `role="radio"`, and `aria-checked` attributes.
- Updated the `payment-method-section.component.html` and `.scss` files to reflect these structural and styling changes.
- The component's inputs have been updated to use Angular's `input()` signal-based API, and helper methods `selectPaymentMethod` and `isSelected` have been added for managing the selection state.
- The `form` input is now a signal-based input and the `paymentMethod` control is accessed via a getter.
* feat(billing): improve billing cycle section ui and functionality
Refactor the billing cycle section to use a more visually appealing card-based radio button selection. This change enhances the user experience by providing clearer visual feedback on the selected option and improving the overall presentation of billing cycle choices.
Key improvements include:
- Custom styling for radio buttons to appear as selectable cards.
- Enhanced hover and selected states for better user interaction.
- Improved typography and spacing for better readability.
- Dynamic styling based on form control value for the selected option.
* feat(subscription-billing-form): calculate and display discounted prices
Implement logic to calculate and display quarterly and yearly subscription prices with appropriate discounts.
The `buildBillingOptions` method has been updated to calculate prices for monthly, quarterly, and yearly billing periods. New helper methods `calculateQuarterlyPrice` and `calculateYearlyPrice` are introduced to handle these calculations, applying discounts for longer billing cycles. The descriptions for quarterly and yearly options have also been refined for clarity.
* fix(ui): adjust subscription billing form button size
Change the size of the "cancel" and "submit" buttons in the subscription billing form from "large" to "medium". This aims to improve the overall visual balance and consistency of the form elements.
* fix(subscription): hide payment section for free plans
Hides the payment section on the subscription billing form when the selected plan is free. This prevents users from being prompted to enter payment details for plans that do not require them.
Added a `isFreePlan` getter to the `SubscriptionBillingFormComponent` to determine if the current plan is free based on its price or type. This getter is now used in the template to conditionally render the payment section and in the `getActionText` method to display a more appropriate button label for free plans.
* feat(plugin-creation): refactor plugin limitations form to use FormArray
This commit refactors the plugin subscription plan creator's limitations form. Previously, limitations were managed using a `FormGroup`, which made it difficult to dynamically add, remove, and manage multiple arbitrary limitations.
The changes include:
- Replacing the `FormGroup` for limitations with a `FormArray`.
- Introducing `createLimitationGroup` and `resetLimitationsArray` methods in the `SubscriptionPlanFormBuilderService` to manage the new `FormArray` structure.
- Updating the component to use the `FormArray` for rendering and managing limitations, including add and remove functionality.
- Adjusting the HTML and SCSS to accommodate the new structure, allowing for more flexible and dynamic limitation management.
- Renaming the `limitations` in the HTML to `limitations-list` for better clarity.
- The `normalizePlanValue` method is updated to correctly handle the new limitations structure.
* fix(subscription-billing-form): apply discount percentage to plan prices
The discount percentage from the `plan` object is now correctly applied to the monthly, quarterly, and yearly prices displayed in the subscription billing form. Previously, discounts were hardcoded or not applied at all.
This change ensures that the pricing reflects the actual discounts available for different billing periods, improving the accuracy of displayed costs to the user.
* fix(subscription-billing-form): change highlighted plan badge text
The highlighted plan badge text has been changed from "Recommended" to "Current". This change better reflects that the badge indicates the user's current plan, not necessarily a recommendation for all users.
* feat(plugin-access): add canConfig$ observable
Implement a new observable `canConfig$` in the `PluginSubscriptionAccessFacade` and `PluginSubscriptionAccessQuery` to determine if a user has the permission to configure a plugin. This logic checks if the plugin's access level is not `PluginScope.USER`. This functionality is then integrated into the `PluginMarketplaceItemComponent` to conditionally display configuration options.
* feat(plugin-marketplace): add dialog for creating subscription plans
Introduces a new dialog component, `DialogSubscriptionPlanCreatorComponent`, which allows users to create new subscription plans for plugins.
This change includes:
- A new action `openPlanCreator` in `PluginPlanActions`.
- An effect `openPlanCreatorDialog$` to handle the opening of the dialog.
- Updates to `PluginMarketplaceItemComponent` to include a button to trigger the dialog.
- The necessary HTML and SCSS for the new dialog.
- Updates to `PluginsModule` to include the new component.
* feat(plugin-marketplace): add dialog mode for subscription plan creator
Introduce a new `dialogMode` input to the `PluginSubscriptionPlanCreatorComponent`.
This mode adjusts the UI and layout to better suit display within a dialog,
improving the user experience for this specific context.
Changes include:
- Setting a fixed width and height for the component in SCSS.
- Passing the `dialogMode` input to the underlying `lib-plugin-subscription-plan-creator` component.
- Conditionally rendering the header section based on `dialogMode` in the HTML.
* fix(plugins): address multiple minor issues and inconsistencies
This commit addresses several minor issues across different packages:
- **RequestContext:** Corrected a typo in the `RequestContext.currentRequest()` call.
- **Available Users Effects:** Implemented pagination for loading users by applying `slice` with `currentSkip` and `currentTake`.
- **Plugin Subscription Plan Creator:**
- Added a check for `normalizedPlanValue` to prevent errors when it's undefined.
- Corrected the spread syntax for `normalizedPlanValue.id` to ensure it's only included if `id` exists.
- **Plugin Settings Management:** Removed an unused `scope` variable.
- **Plugin Subscription Hierarchy:** Added optional chaining (`?.`) to `subscription.plan.price` to safely access the price.
- **Plugin Subscription Plan Selection:**
- Updated `window.removeEventListener` and `window.addEventListener` to use a bound handler for `handleKeyboardShortcut` to ensure correct context.
- Added optional chaining (`?.`) to `currentPlan?.id` for safe access.
- **Plan Comparison Service:** Added a check for `currentPlan` to return early if it's null.
- **Form Data Builder:**
- Filtered out falsy values from `plans` before mapping in `appendSubscriptionPlans`.
- Corrected the spread syntax for `plan.id` to ensure it's only included if `id` exists.
- **List Plugin Subscription Plans Handler:** Removed an unused `relations` variable.
- **Auto Tag Plugin Handler:** Removed an unused `overwriteExisting` option from `options`.
- **Manage Plugin Tenant Users Handler:** Adjusted logging to correctly display the number of users, handling cases where `userIds` might be null.
- **Update Plugin Command Handler:** Added optional chaining (`?.`) to all input properties being mapped to `pluginUpdate` for safer access.
- **Plugin Billing Factory:** Removed unnecessary status assignment for `PluginBillingStatus.PENDING`.
- **Plugin Subscription Access Service:** Removed the `SubscriptionValiditySpecification` as it was not being used.
- **Plugin Subscription Plan DTO:** Removed the unused `transformToNumber` helper function.
* fix(plugin): improve input validation and data handling
This commit addresses several issues related to input validation and data handling within the plugin registry.
In `create-plugin-command.handler.ts`, the validation logic has been refined to more accurately check for required version information, particularly when `version.sources` is present but empty. The destructuring of `input` has also been moved after the validation to prevent potential errors.
In `update-plugin-command.handler.ts`, a check for `input` being null or undefined has been added before attempting to access its properties, preventing potential runtime errors. Additionally, the update logic now correctly uses `input.propertyName` instead of `input?.propertyName` for mandatory fields.
In `plugin-billing.controller.ts`, the condition for applying search filters has been made more explicit by introducing a `hasFilters` variable, improving readability. This change ensures that filters are only applied when there are actual search options defined.
* fix(plan-comparison): handle missing currentPlan.price gracefully
The `currentPlan.price` could be undefined, leading to an error when trying to parse it with `this.parsePriceAsNumber`. This change ensures that if `currentPlan.price` is undefined, it defaults to 0 for calculations, preventing potential runtime errors.
* fix(plugin-marketplace): adjust styling for plugin marketplace layout
Adjusted several CSS styles within the plugin marketplace component to improve the layout and visual presentation. This includes:
- Correcting the `border-radius` for the first plugin card to ensure proper rounding.
- Adding `max-height: unset !important;` to the plugin subscription plan creator to prevent unexpected height constraints.
- Modifying the `marketplace-container` class to include `content-active first` for better initial rendering.
- Removing `class="content-active first plugin-list"` from the `lib-plugin-list` directive and updating the `plugin-list` styles in `plugin-marketplace.component.scss` to include `position: sticky`, `top: 0`, and a specific `height`.
- Refactored the `.grid-view` selector in `plugin-marketplace.component.scss` for better specificity.
- Updated `plugin-list` styles to set `height`, `padding`, and `background-color`, replacing the `max-height: none !important;` override.
* fix(desktop-ui-lib): reset max-height for plan card
The `max-height: fit-content` property on the plan card component was causing issues with its display, especially when the content within the card exceeded its natural height. This change sets `max-height` to `unset`, allowing the card to expand and accommodate its content properly.
* fix(plugin-marketplace): add unavailable and loading states
Add CSS classes to the plugin list component to visually indicate when the plugin marketplace is unavailable or in a loading state. This improves user experience by providing feedback on the status of the marketplace.
- Adds `.unavailable` class when `!available && !isLoading`.
- Adds `.loading` class when `isLoading`.
- Styles for these classes are added in the SCSS file to adjust layout and content visibility.
* fix(plugin): update plugin subscription model and UI
The `IPlugin` interface has been updated to use `subscriptions` (an array of `IPluginSubscription`) instead of `subscription` (a single `IPluginSubscription`). This change allows for multiple subscriptions per plugin, which is a more flexible and realistic representation.
The UI for displaying plugin subscriptions has also been refactored to accommodate this new structure. It now correctly handles the array of subscriptions and displays the first one if available, or provides a more accurate representation of subscription status and details. Styling adjustments were also made to improve the visual presentation of subscription information in different view modes.
* feat(contracts): Add new plugin-related interfaces and enums
This commit introduces several new interfaces and enumerations to the `@gauzy/contracts` package, specifically related to plugins and their functionalities. These additions provide a more comprehensive and structured way to define and manage plugins, their subscriptions, billing, settings, and tenant configurations.
Key additions include:
- `PluginSettingDataType`: Enum for different data types of plugin settings.
- `PluginBillingStatus`: Enum for various statuses of plugin billing.
- Enhanced `IPluginSubscription`, `IPluginSubscriptionPlan`, `IPluginSetting`, `IPluginBilling`, and `IPluginTenant` interfaces with more detailed properties and clearer documentation.
- Introduction of `IPluginTag` interface to represent plugin-tag relationships.
- Updated `IPlugin` interface to include `isFeatured` and `isVerified` properties.
- The `PluginScope` enum was moved from a separate model to the contracts package.
- Various other enums and interfaces were consolidated or refined for better clarity and consistency.
* refactor(plugins): optimize database indexes and remove console log
This commit introduces several improvements to the plugins domain:
- **Database Index Optimization:** New indexes have been added to various plugin-related entities (`PluginInstallation`, `PluginSource`, `PluginSubscription`, `PluginVersion`, `Plugin`) to improve query performance. These indexes are strategically placed to optimize common lookups based on tenant, organization, plugin ID, status, and other relevant fields.
- **Removed Unnecessary Console Log:** The `console.log` statement in `PluginSubscriptionPlanSelectionComponent` has been removed. This statement was used for debugging purposes during development and is no longer needed in production code.
These changes contribute to better database performance and cleaner code.
* fix(registry): update unique and index constraints
Add `installedById` to the unique constraint for plugin installations to prevent duplicate installations by the same user within the same context. Also, add a new index on `installedById` and `pluginId` for improved query performance when retrieving installations by a specific user and plugin.
* fix(plugin-marketplace): improve layout and add null checks
Addresses visual inconsistencies and potential runtime errors in the plugin marketplace detail view.
The following improvements have been made:
- Added nullish coalescing operator (`?.`) to safely access nested properties of `plugin` and `subscription` objects, preventing potential errors if these are undefined.
- Refactored SCSS for the list view to utilize flexbox for better responsiveness and adaptability across different screen sizes.
- Adjusted styling for various elements within the list view to improve readability and visual hierarchy, including plugin name, meta, badges, description, and actions.
- Enhanced the display of subscription information by wrapping elements to ensure they remain visible on smaller screens.
- Implemented `text-overflow: ellipsis` and `white-space: nowrap` for the toggle label to handle long plugin names gracefully.
* fix(plugin-marketplace): add padding to plugin action buttons
Adds 4px top/bottom and 8px left/right padding to the action buttons within the plugin marketplace detail view. This improves visual spacing and usability of these interactive elements.
* fix(plugin-marketplace): add gap to subscription type display
Add a gap of 0.5rem between the icon and the text in the subscription type display. This improves the visual spacing and readability of plugin subscription details.
* chore: update cspell dictionary and fix typo
Add new words to the cspell dictionary to improve code spell checking.
Also, fix a minor typo in a comment in the plugin entity file.
* refactor(plugins): adjust ORM column types and constraints
Adjusts ORM column definitions in plugin-related entities to improve database compatibility and integrity.
- `PluginInstallation`: conditionally sets `length: 36` for UUID relation IDs only when not using PostgreSQL, preventing unnecessary length constraints.
- `PluginTag`: uses a function call `isBetterSqlite3()` for the `timestamp` type comparison, ensuring correct behavior across different ORM configurations.
- `PluginTenant`:
- explicitly sets `type: 'uuid'` for `pluginId` and `approvedById` relation IDs for clarity.
- changes `onDelete` from `'SET NULL'` to `'CASCADE'` for many-to-many relations (`allowedRoles`, `allowedUsers`, `deniedUsers`). This ensures that when a plugin tenant is deleted, the corresponding entries in the pivot tables are also removed, maintaining data consistency.
* fix(migrations): update migration to create plugin tables
This commit updates the database migration script for creating plugin marketplace tables. The changes include:
- Renaming the migration file to reflect a later timestamp.
- Updating the migration class name to match the new file name.
- Correcting the data types and constraints in the SQL statements to align with the database schema.
- Adjusting ENUM types and table definitions for 'plugin_tenants' and 'plugin_settings' to match expected structure.
- Ensuring all related indexes and foreign key constraints are correctly generated.
- Making adjustments to the temporary table creation and renaming process to ensure data integrity during the migration.
- Correcting syntax and type definitions for SQL queries.
* feat(plugin-subscription): refactor plan creator UI and logic
Refactors the plugin subscription plan creator component with significant UI and logic improvements. This commit introduces:
- **Enhanced UI:** Modernized styling for alerts, headers, plan cards, and form elements for a cleaner and more intuitive user experience.
- **Improved Loading States:** Implemented per-plan loading indicators and a general loading state for initialization.
- **Success Messages:** Added user-facing success messages for plan updates and creations.
- **Advanced Options:** Introduced a collapsible section for additional plan options (trial days, setup fee, discount, popular/recommended flags).
- **Conditional UI Rendering:** Additional options are now hidden for free plans or plans with a price of 0.
- **Input Validation Enhancements:** Improved visual feedback for required fields and added validation summaries.
- **Plan Type Selection:** Redesigned plan type selection with clearer visual options and icons.
- **Code Structure:** Refactored the component to improve readability and maintainability, including the introduction of `isPlanLoading` and `isAdvancedOptionsExpanded` methods.
- **Error Handling:** Modified alert display and reset functionality for better error management.
- **Feature and Limitation Management:** Streamlined the UI for adding and removing features and limitations.
- **Empty State:** Improved the empty state for when no plans are created.
- **Loading/Initialization State:** Added a loading state while the component initializes.
* feat(plugin-marketplace): implement plan creation dialog
Refactor the plugin plan creation dialog to correctly dispatch the bulkCreatePlans action. Previously, the dialog was not correctly handling the creation of new plans.
This change involves:
- Updating the `PluginPlanActions.bulkCreatePlans` action to accept `Partial<IPluginSubscriptionPlan>` instead of a more restrictive type.
- Modifying the `DialogSubscriptionPlanCreatorComponent` to dispatch the `bulkCreatePlans` action with the provided plan data.
- Introducing a subscription to `PluginPlanQuery.creating$` to wait for the creation process to complete before closing the dialog, providing better user feedback.
- Removing the `TODO` comment related to saving new plans.
* feat(dialog-subscription-plan-creator): add loading state to save button
Adds a loading spinner to the save button in the subscription plan creator dialog while the plans are being created. This improves user feedback by indicating that an action is in progress.
The save button is now disabled while `creating$` is true, preventing multiple submissions. An `@let` statement is introduced to handle the `creating$` observable in the template, and the `nb-icon` with the `gauzySpinner` directive is conditionally shown based on the `creating` state.
* fix(plugin-marketplace): conditionally render pricing fields for free plans
This commit addresses an issue where pricing fields were incorrectly displayed and editable for "free" subscription plans. The changes ensure that pricing-related fields (price, billing cycle, currency) are only shown and modifiable when the selected subscription plan type is not FREE.
Additionally, this commit includes:
- Minor cleanup in the `PluginPlanEffects` by removing an unnecessary type annotation.
- Removal of a specific gradient background from the upload component's SCSS, which was no longer needed.
- Adjustment of margin-top for the pricing preview section in the SCSS for better visual spacing.
- The `selectPlanType` method in the `PluginSubscriptionPlanCreatorComponent` now automatically sets the price to 0 when the plan type is changed to FREE, preventing accidental price input for free plans.
* fix(plugin-marketplace): adjust subscription plan limits and scope
Update the default `maxUsers` for FREE/TRIAL and BASIC subscription plans to 1.
Also, adjust the `PluginScope.USER` to be returned for the BASIC plan, aligning it with FREE and TRIAL plans.
This change aims to refine the user and organization scope for different subscription tiers.
* fix(plugin-marketplace): improve subscription plan creation UI and logic
- Add optional chaining for `subscription?.scope` to prevent errors when subscription is null.
- Update spinner directive from `gauzySpinner` to `gauzySpinnerButton` for better integration with buttons.
- Initialize `isPlanValid` to `false` and update its logic to also consider `plans.length > 0` for accurate validation.
- Dispatch `bulkCreatePlans` action using the `Actions` service for better state management.
- Add a `gap` of `1rem` to the `nb-button-group` in `plugin-marketplace.component.scss` for improved spacing.
* feat(plugin-plans): implement bulk create plugin plans
Introduces a new endpoint and functionality to create multiple plugin subscription plans simultaneously.
This change refactors the plugin plan creation process from sequential individual calls to a single bulk operation. This improves efficiency and reduces the overhead of multiple API requests.
The `PluginPlanActions.bulkCreatePlans` action in the desktop UI library now dispatches a single action to the backend. The backend service `PluginSubscriptionService.bulkCreatePlans` handles the batch creation, and the `BulkCreatePluginPlansHandler` in the plugin registry orchestrates the transaction.
A new DTO `CreateMultiplePluginPlansDTO` and corresponding command `BulkCreatePluginPlansCommand` have been introduced to support this functionality.
The `canConfig$` observable in `plugin-subscription-access.query.ts` has been updated to safely handle potential null states with optional chaining.
* feat(plugin-plan): add reset errors action and effect
Introduce a new action `resetErrors` to the `PluginPlanActions` and a corresponding effect in `PluginPlanEffects`. This allows for explicitly resetting error states related to plugin plans.
The `PluginSubscriptionPlanCreatorComponent` is updated to call this new `resetErrors` method when the error alert is closed or when the component is destroyed. This ensures that error messages are cleared appropriately, improving the user experience.
Additionally, several template updates were made to use Angular's `@if` and `@for` syntax for better reactivity and to simplify conditional rendering and looping. The styling for loading and empty states in the SCSS file has also been refined for a more polished look and feel.
* fix(registry): handle duplicate plan names more robustly
The previous implementation of checking for duplicate plan names did not properly account for cases where `findOneByWhereOptions` might not return a record. This commit updates the logic to use `findOneOrFailByWhereOptions` and checks the `success` flag to ensure a duplicate plan is only considered an error if one actually exists and is not the current plan being updated. This prevents potential false positives and ensures the uniqueness constraint is enforced correctly.
* fix(plugin-subscription): refactor command handlers and domain logic
Refactors several command handlers and the `PluginSubscription` domain logic to improve clarity, maintainability, and adherence to the domain-driven design principles.
Key changes include:
- **Command Handler Refactoring:**
- Modified `DeletePluginSubscriptionCommand` to accept `subscriptionId` and `pluginTenantId` for more precise deletion logic.
- Enhanced `CancelPluginSubscriptionCommandHandler` to leverage domain methods (`cancel`) for business logic and cascade cancellations to child subscriptions.
- Updated `DowngradePluginSubscriptionCommandHandler` to use domain methods and simplify child downgrading.
- Improved `ExtendTrialSubscriptionCommandHandler` by directly using domain methods and cascading trial extensions.
- Refined `PurchasePluginSubscriptionCommandHandler` to handle existing subscriptions more robustly by deleting them via `DeletePluginSubscriptionCommand` and ensuring proper `pluginTenant` creation.
- Modified `RenewPluginSubscriptionCommandHandler` to use domain methods for renewal and cascade to child subscriptions.
- Updated `UpgradePluginSubscriptionCommandHandler` to use domain methods for upgrades and cascade to child subscriptions.
- **Domain Logic Enhancements:**
- `PluginSubscription.cancel()` now handles removing the subscriber from `pluginTenant.allowedUsers` and sets `planId` to null.
- `PluginSubscription.downgradeToPlan()` and `upgradeToPlan()` now directly update child subscriptions within the domain model.
- `PluginSubscription.renew()` now correctly handles child renewals and updates metadata.
- `PluginSubscription.extendTrial()` now cascades trial extensions to child subscriptions.
- **Service Improvements:**
- `PluginTenantService` now uses `findOneOrFailByIdString` for better error handling and ensures tenant existence before operations.
- Added `exists` method to `PluginTenantService`.
- Added `upsert` method to `PluginSubscriptionService`.
- **Controller Update:**
- Modified the `delete` endpoint in `PluginSubscriptionController` to accept both `id` (subscriberId) and `pluginTenantId`.
* fix(registry): add user validation and improve get users query
Adds validation to prevent operations on the current user within the `ManagePluginTenantUsersCommandHandler`.
Refactors the `GetPluginTenantUsersHandler` to use TypeORM queries for improved performance and correctness when fetching plugin tenant users. This change directly queries the database to determine allowed and denied users, also applying search filters and pagination more efficiently. It also excludes the current user from the results.
* fix(plugin-user-management): exclude current user from available users
Removes the current user from the list of available users in the plugin user management component. This prevents users from assigning themselves to a plugin they are already managing or have access to.
* fix(plugin-user-assignment-dialog): remove unused imports
Removes unused TranslateService and ToastrNotificationService imports from the plugin user assignment dialog component. These services were not being used within the component and have been removed to clean up the code.
* fix: Adjust UI padding and effect logic, improve cancellation
Refactor:
- Adjusted padding and gap values in `plugin-marketplace.component.scss` for better visual consistency across different screen sizes.
- Removed `includeInactive` parameter from `loadAssignments` and `loadMoreAssignments` effects in `plugin-user-assignment.effects.ts` as it was not being used.
- Enhanced `CancelPluginSubscriptionCommandHandler` in `cancel-plugin-subscription.handler.ts` to:
- Prevent cancellation if the subscription is already cancelled by adding `status: Not(PluginSubscriptionStatus.CANCELLED)`.
- Filter children subscriptions to only cancel those that `canBeCancelled()`, ensuring more robust cancellation logic.
* feat(plugin-subscription): refresh plugin access on subscription change
Add a new effect to trigger a refresh of plugin access whenever a plugin subscription is successfully created, updated, canceled, upgraded, or downgraded. This ensures that the user's access to plugins is always up-to-date with their current subscription status.
Also, update the PluginMarketplaceStore to correctly set the subscription on the plugin and in the list of plugins when a subscription change occurs. This is crucial for reflecting the latest subscription information throughout the application.
* fix(ui): adjust scss for plugin marketplace tabs
This commit refactors the SCSS styles for the plugin marketplace tabs, including the Overview, Settings, and User Management tabs. The changes aim to improve visual consistency, responsiveness, and code organization. Specific adjustments include:
- **Padding and spacing:** Fine-tuning padding and gap values for better layout on various screen sizes.
- **Card styling:** Standardizing card appearance and hover effects.
- **Icon sizing and placement:** Ensuring icons are appropriately sized and positioned.
- **Responsive adjustments:** Implementing responsive styles for smaller viewports to maintain usability.
- **Code readability:** Organizing selectors and properties for better maintainability.
* fix(registry): remove unused variable in updateScope
The `record: pluginTenant` variable was being destructured from the `findOneOrFailByIdString` call but was not being used within the `updateScope` method. This commit removes the unused variable to clean up the code.
* Update .github/instructions/angular.instructions.md
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Update packages/core/src/lib/core/context/request-context.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: adkif <akifungo@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>